4.8 KiB
Panoramica dell'architettura
Sintesi ad uso documentazione. Per il dettaglio storico delle decisioni di design vedi le Specifiche di Design e i Piani di Implementazione. Per lo stato corrente del progetto (gate manuali pendenti, layout workspace/secret) vedi
PROJECT_STATE.mdnella radice del repo.
ThothII è un datamart builder human-in-the-loop: trasforma una domanda in linguaggio naturale in SQL validato (ed eventualmente un datamart dbt) attraverso un workflow deterministico a 8 fasi NL→SQL, in cui il modello propone e un revisore umano decide ai gate.
I tre progetti indipendenti
frontend (React/SSE) → backend (Fastify) → pi --mode rpc → tht/harness → DWH (sola lettura)
| Layer | Stack | Ruolo |
|---|---|---|
| harness/ | Python (tht CLI) + Pi gate extension (JS) |
Possiede il workflow e tutta la persistenza |
| backend/ | Fastify + TypeScript | Ponte sottile senza database proprio |
| frontend/ | React 18 + Vite | UI che renderizza i widget di gate e ricostruisce il transcript live dallo stream SSE |
L'harness possiede il workflow
tht (Python) è una CLI deterministica; harness/.pi/extensions/tht-gate.js è un'estensione Pi che guida il workflow a 8 fasi. La fonte di verità unica del workflow è harness/workflow.yaml; le regole di orchestrazione che il modello deve seguire sono in harness/.pi/skills/tht-sessione/SKILL.md. La "fase corrente" non è memorizzata: viene calcolata piegando il decision ledger (harness/tht/phase.py) — va letta prima di ragionare sulla logica di fase.
Persistenza = documenti di fase, non chat
Una sessione è una directory sotto sessions/ (path definito dal workspace): session_manifest.yaml + artefatti per fase (question.md, schema_linking.json, sql_final.sql, …) + review_decisions.jsonl. Il contratto (SKILL.md): "lo stato persistito è la verità — ciò che non è registrato non è accaduto". Non esiste uno store di transcript verbatim. Un processo Pi ripreso ricostruisce il contesto da tht session show <id> + gli artefatti su disco.
Il backend è un ponte sottile senza database
ThtRunneresegue subcommandthtin shellPiProcessManageresegue un processo Pi figlio per sessione e fa da bridge al suo stream RPCSessionBridgemappa eventi RPC di Pi → eventi client (ui_request/text_delta/info)SseHubdistribuisce questi eventi via SSE al browser
Le impostazioni applicative vivono in un file JSON (backend/data/settings.json), non in un database.
Contratto del gate human-in-the-loop
Il modello propone; un revisore umano decide ai gate tramite widget:
reviewer_select— scelta singola: un'opzione condecisionpayload auto-conferma/persiste direttamente; un'opzione senza payload chiede soltantoreviewer_decide— multiselect: ogni scelta È una decisionereviewer_confirm— gate su artefatto/fase
Il frontend renderizza questi widget-descriptor (registro in src/widgets/); il transcript live viene ricostruito in memoria dallo stream SSE (src/store/sessionStore.ts) — non è persistito.
Punti di attenzione ricorrenti
tht -c/--configè un'opzione per-comando: deve seguire il subcommand, mai precederlo (ThtRunner.buildArgvlo impone).- L'output
--jsondeve essere JSON puro su stdout — è un contratto machine-readable. - Le stringhe UI sono in inglese; il contenuto dei documenti resta nella lingua del workspace (italiano per
psd), perché è il dato reale — solo chrome/label sono in inglese. - I workspace (
harness/workspaces/*.yaml) impostano il target DB e i path assolutipaths.sessions/artifacts/indexes— perpsdpuntano a un repo separato e non versionato (tht-workspace-psd/). I segreti vivono solo inharness/.env(gitignored). - Le impostazioni sono globali (
backend/data/settings.json: workspace/provider/modello/thinking); il form di nuova sessione richiede solo la domanda. - Resume: una sessione riprendibile rientra all'ultima fase incompleta. Il backend rifiuta il resume con 409 se
finalizedoarchived;PiProcessManager.spawnFordeve inviare/riprendi-sessione <id>(resume) vs/nuova-domanda(nuova) — il prompt sbagliato trasforma silenziosamente un resume in una nuova domanda.
Come si lancia lo stack
Lo stack locale si avvia con ./scripts/run-stack.sh, dopo aver creato
deploy/env/local.env da deploy/env/local.env.example. Il core Compose include Pi; DWH,
vector DB, embedding e LLM sono endpoint esterni configurati nel file locale.
Comandi per singolo layer, test, lint: vedi il file CLAUDE.md nella radice del repo (guida operativa per Claude Code, tenuta sincronizzata con questa pagina).