Metadata-Version: 2.4
Name: sintropi-bootstrap
Version: 2605.14.1516
Summary: Bootstrap and launcher for the sintropi-code CLI — authenticates via Keycloak PKCE and pulls the right engine version from each Sintropi gateway.
Project-URL: Homepage, https://bitbucket.org/eight-twenty/sintropi-bootstrap
Author-email: Eight20 <dev@eight-twenty.com>
License: Proprietary
Requires-Python: >=3.9
Requires-Dist: click>=8.0
Requires-Dist: requests>=2.28
Description-Content-Type: text/markdown

# sintropi-bootstrap

Bootstrap pubblico per la CLI `sintropi-code` — l'engine multi-agent di **Sintropi**.

Permette a uno sviluppatore di installare, autenticare e mantenere allineata la versione di `sintropi-code` corretta per ogni tenant Sintropi (dev, qa, prod, cliente).

## Installazione

```bash
pip install sintropi-bootstrap
```

## Upgrade

```bash
pip install --upgrade sintropi-bootstrap
```

`sintropi-bootstrap` si aggiorna da solo: scarica automaticamente la versione aggiornata dell'engine `sintropi-code` a ogni rilascio del tenant. Di norma non è necessario reinstallarlo manualmente.

## Uso

```bash
# Primo setup o switch tenant (idempotente)
sintropi-bootstrap https://mcp.acme.eight20.com

# Comando principale — auto-detect versione, auto-download se cambiata
sintropi-code generate "App per la gestione ordini"
sintropi-code bootstrap my-app -o ./output/my-app
```

## Come funziona

### 1. `sintropi-bootstrap <mcp_url>`

```
sintropi-bootstrap https://mcp.acme.eight20.com
→ Leggo config del server MCP
→ Autenticazione Keycloak — Device Authorization
  [apre il browser sulla pagina Keycloak standard]
  [attende che l'utente inserisca il codice]
→ MCP configurato in ~/.claude/settings.json
→ Scarico engine wheel...
→ Installo engine in venv isolato...
✓ Server attivo: https://mcp.acme.eight20.com
  Usa: sintropi-code [args]
```

Passi dettagliati:

1. `GET {mcp_url}/api/bootstrap/config` (pubblico) → `{ keycloak_url, realm, client_id, current_sha, current_version }`
2. Avvia **Device Authorization Grant (RFC 8628)** — apre il browser sulla pagina Keycloak, mostra un codice da inserire, nessuna porta localhost richiesta
3. Configura automaticamente **Claude Code** scrivendo il server MCP in `~/.claude/settings.json` con il Bearer JWT
4. Verifica che l'utente abbia il ruolo realm Keycloak `sintropi-code`
5. Scarica il wheel via `GET {mcp_url}/api/bootstrap/download` (Bearer JWT)
6. Crea un venv isolato in `~/.sintropi/versions/{sha}/.venv/` e ci installa `sintropi-code`
7. Registra il server in `~/.sintropi/config.json`

### 2. `sintropi-code [args]`

1. Legge il server MCP corrente da `~/.sintropi/config.json`
2. Verifica (con cache TTL 5 min) il SHA dell'engine corrente del server
3. Se diverso o assente → re-auth + download + install (trasparente) + aggiorna `~/.claude/settings.json`
4. `exec` in `~/.sintropi/versions/{sha}/.venv/bin/python -m sintropi_code.main <args>`

## Architettura MCP

`sintropi-bootstrap` configura Claude Code come client del server MCP del tenant Sintropi. Ogni tenant espone un server MCP all'URL `https://mcp.<tenant>.eight20.com`.

```
┌────────────────────────────────────────────────────────────┐
│  Claude Code (IDE / Claude Desktop / Cowork)               │
│  ~/.claude/settings.json → mcpServers.sintropi             │
└───────────────────────┬────────────────────────────────────┘
                        │  HTTP  Bearer JWT
                        ▼
┌────────────────────────────────────────────────────────────┐
│  Sintropi MCP Server  (https://mcp.<tenant>.eight20.com)   │
│  • Tools: genera, lista, pubblica artefatti                │
│  • Auth: Keycloak JWT (realm per tenant)                   │
│  • Engine: scarica sintropi-code wheel                     │
└───────────────────────┬────────────────────────────────────┘
                        │  GraphQL / REST
                        ▼
┌────────────────────────────────────────────────────────────┐
│  Sintropi Platform (gateway + DB + storage)                │
└────────────────────────────────────────────────────────────┘
```

`sintropi-bootstrap` esegue lo **scaffolding iniziale** una volta sola (o al cambio di tenant/versione):

- ottiene il JWT con Device Grant (senza porte localhost)
- scrive il JWT in `~/.claude/settings.json` sotto `mcpServers.sintropi`
- installa la versione corretta dell'engine in un venv isolato

Dopo il bootstrap Claude Code comunica **direttamente** con il server MCP tramite HTTP, aggiornando il token quando scade.

### Autenticazione: Device Authorization Grant (RFC 8628)

Il flow predefinito non richiede una porta localhost. Funziona da qualsiasi ambiente: desktop, container remoto, sandbox cloud (Cowork), CI/CD interattivo.

```
CLI                    Keycloak                  Browser utente
 |                        |                            |
 |-- POST /auth/device --> |                            |
 |<-- device_code, -------|                            |
 |    user_code,          |                            |
 |    verification_uri    |                            |
 |                        |                            |
 |-- stampa user_code --> terminale                    |
 |-- apre browser ------> verification_uri ----------> |
 |                        |<-- utente inserisce -------|
 |                        |    user_code + login       |
 |                        |                            |
 |-- POST /token (poll) ->|                            |
 |<-- access_token -------|                            |
```

Il CLI stampa il codice sul terminale e lo apre nel browser automaticamente. L'utente lo inserisce nella pagina Keycloak standard. Il CLI ottiene il token senza mai aprire una porta.

### Autenticazione: PKCE loopback (legacy)

Il flow PKCE su loopback (`http://localhost:PORT`) è ancora disponibile nel modulo `keycloak.login_pkce()` per ambienti locali che preferiscono il redirect automatico. Non è più il flow predefinito.

## Layout filesystem

```
~/.sintropi/
├── credentials.json    # token per-server (chmod 600)
├── config.json         # server noti + current + ultimo check
└── versions/
    ├── {sha-abc123}/
    │   ├── .venv/      # venv isolato con sintropi-code installato
    │   └── manifest.json
    └── {sha-def456}/
        ├── .venv/
        └── manifest.json

~/.claude/
└── settings.json       # configurazione MCP aggiornata da sintropi-bootstrap
```

Ogni server MCP può avere una versione diversa dell'engine. La cache locale supporta più tenant simultaneamente: switchare è istantaneo se la versione è già scaricata.

## Switch tenant

`sintropi-bootstrap` è **idempotente**. Rilanciarlo con un URL diverso fa lo switch:

```bash
sintropi-bootstrap https://mcp.dev.acme.eight20.com    # tenant dev
sintropi-code generate "..."

sintropi-bootstrap https://mcp.prod.acme.eight20.com   # switch a prod
sintropi-code generate "..."   # ora usa l'engine di prod
```

Override puntuale senza cambiare il default:

```bash
sintropi-code --mcp https://mcp.qa.acme.eight20.com generate "..."
```

## Permesso negato (ruolo mancante)

Per scaricare l'engine serve il ruolo realm Keycloak `sintropi-code`. Se sei loggato ma il ruolo non è assegnato, `sintropi-bootstrap` (e `sintropi-code`) stampano un riquadro con le istruzioni:

```
────────────────────────────────────────────────────────────────────────
 Permesso negato: ruolo mancante
────────────────────────────────────────────────────────────────────────

 Utente:        mario.rossi@eight-twenty.com
 Realm:         acme
 Ruolo serve:   sintropi-code

 Come richiedere l'accesso:

 1. Contatta l'amministratore Keycloak del realm 'acme' e chiedi
    di assegnarti il ruolo realm 'sintropi-code'.

 2. L'admin può farlo dalla console Keycloak:
    https://auth.acme.eight20.com/admin/acme/console/
    → Users → mario.rossi@eight-twenty.com → Role mapping → Assign role → sintropi-code

 3. Una volta assegnato il ruolo, rilancia lo stesso comando:
    il token verrà rinnovato automaticamente e il download partirà.
```

L'errore esce con exit code `2`.

## Uso da Claude Cowork e ambienti sandbox

`sintropi-bootstrap` usa il **Device Authorization Grant** come flow predefinito, quindi non apre mai una porta localhost. Funziona nativamente in:

- **Claude Desktop / Cowork locale** — browser di sistema aperto automaticamente
- **Claude Code web / Cowork cloud** — il link viene aperto fuori dalla sandbox tramite il meccanismo "Apri in Chrome" di Cowork; l'utente inserisce il codice nella pagina Keycloak
- **Container / VM remota** — il link viene stampato sul terminale; l'utente lo apre sul browser locale
- **CI/CD interattivo** — identico al caso container

Dopo il bootstrap il token JWT è in `~/.claude/settings.json`. Claude Code lo usa direttamente per le chiamate al server MCP — non passa per localhost.

## Sicurezza

- **Device Grant**: nessun secret nel pacchetto, nessuna porta esposta
- **PKCE loopback** (legacy): nessun secret, redirect su `http://localhost:PORT` random con state CSRF
- **Token scope**: `openid profile email offline_access`
- **Role check server-side**: il server MCP nega il download senza ruolo `sintropi-code`
- **SHA-256 verificato** sul wheel scaricato (oltre al TLS)
- **credentials.json** salvato con permessi `0600`
- **MCP Bearer JWT** scritto solo in `~/.claude/settings.json` (file locale utente)

## Licenza

Proprietary — © Eight20.
