Questa pagina racconta com’è assemblata Calíope: su quali framework poggia, dove passa il confine con il motore, cosa permette la sandbox e cosa l’app non fa di proposito. Ogni cifra viene dall’albero dei sorgenti, a ottobre 2026.
Un’app, tre binari
Calíope si distribuisce come una sola app, org.caliope.caliope, con acquisto universale: un acquisto copre tutti i dispositivi Apple su cui gira. Dietro quella sola app ci sono tre binari: uno per macOS, uno per iPhone, iPad e Apple Vision Pro (lo stesso target, compilato per iOS e per visionOS — l’app per Apple Watch viaggia incorporata nella build per iOS) e uno per Apple TV.
La maggior parte del codice non si scrive tre volte. Sources/Shared contiene 367 file Swift e 277 view SwiftUI che compilano sia nel binario per Mac sia in quello per iOS. I widget sono estensioni della stessa app e leggono ciò che l’app pubblica attraverso un App Group; l’app scrive, il widget legge soltanto.
SwiftUI da cima a fondo
Ogni finestra è SwiftUI nativo — nessuna web view, nessuna emulazione multipiattaforma. Quella frase è nella home page ed è letteralmente vera: le 277 view condivise sono SwiftUI, e dove un Mac e un iPad devono comportarsi in modo diverso, la differenza si decide in compilazione, nello stesso file, non in uno strato di compatibilità a tempo di esecuzione.
Il confine con il motore
Tutto ciò che parla con un motore di database vive dietro 16 protocolli in Sources/Models/Database/Protocols/, raggruppati per sotto-area. Ogni motore ha un’implementazione di quei protocolli, e nulla sopra il confine — né una view, né l’orchestratore — scrive SQL o conosce i codici di errore di un motore. Aggiungere un motore significa implementare i protocolli, non modificare chi li chiama.
Calíope parla con nove motori, e il codice che parla con loro viene da due posti.
- Sette passano per un client che ho scritto io. Sei a partire dal protocollo che pubblica il loro produttore: MySQL e MariaDB via il loro protocollo client/server, PostgreSQL via il suo protocollo frontend/backend, SQL Server via TDS, MongoDB via
OP_MSGe BSON, ClickHouse via la sua interfaccia HTTP o HTTPS, e Redis via RESP2 e RESP3. Oracle Database parla TNS: Oracle non ne pubblica la specifica, quindi scrivo a partire dal codice che indica come riferimento pubblico, il suo driver Python. Ognuno implementa ciò che Calíope usa e niente di più; i sette strati di protocollo stanno in circa 18.700 righe. - Due non hanno alcun driver: il motore stesso gira dentro l’app. SQLite è la libreria che arriva con il sistema, e l’editor SQLite le parla attraverso la sua API C. DuckDB 1.5.5 è il codice sorgente di DuckDB Labs, compilato dentro l’app come pacchetto locale con un sottile strato Swift sulla sua API C, e non scarica alcuna estensione — quelle incluse sono tutte quelle che ci sono.
Il codice di rete gira su SwiftNIO 2.101.0, la libreria di rete open source di Apple; l’eccezione è il client ClickHouse, scritto su URLSession (versioni a ottobre 2026). Le query con parametri usano il prepared statement del protocollo di ciascun motore — COM_STMT_PREPARE e COM_STMT_EXECUTE su MySQL e MariaDB, il protocollo di query esteso (Parse, Bind, Execute) su PostgreSQL, sp_executesql via RPC su SQL Server, bind :1 nella chiamata di esecuzione su Oracle Database, parametri tipizzati {nome:Tipo} su ClickHouse —: i valori viaggiano nel protocollo di rete e non vengono mai concatenati nell’SQL. Quello che scrivi nell’editor viene inviato così come l’hai scritto.
Il client MongoDB copre OP_MSG, BSON, SCRAM-SHA-1 e SCRAM-SHA-256, e la risoluzione SRV di mongodb+srv:// con il DNS di sistema, e supporta MongoDB 4.0 o successivo. MongoDB resta fuori dal confine con il motore di proposito: nessuna view tocca questo strato di protocollo, e l’intero strato MongoDB è progettato per poter essere rimosso senza toccare il lato relazionale. Anche Redis vive fuori, con una sessione propria.
Perché scrivo i driver
Un’app di database i cui driver sono scritti tutti da una sola persona merita una domanda: chi li mantiene funzionanti quando un server cambia? Ecco la mia risposta, e ciò che puoi verificare.
Non è una novità per me. Prima di Calíope ho scritto gb.mysql, il componente MySQL del linguaggio Gambas; Gambas lo ha accolto nel 2008 e lo include ancora oggi con il mio nome. Calíope stessa è nata quello stesso anno come app Qt che parlava con MySQL e MariaDB chiamando direttamente la loro API C, attraverso uno strato di database che ho scritto io; il suo codice sorgente è nella pagina delle versioni precedenti in Qt. Di tutto questo mestiere, lo strato tra un’applicazione e il suo database è la parte che faccio da più tempo.
Ne scrivo uno quando dipendere da altri è il rischio maggiore. Calíope ha usato un driver MongoDB della comunità fino alla versione 1.5 inclusa. Quando il suo sviluppo si è fermato, l’ho sostituito con il mio.
Un driver stretto è un driver piccolo. Un driver di uso generale deve servire ogni applicazione; i miei ne servono una. Per questo sono abbastanza piccoli da permettermi di sapere cosa fa ogni parte.
Possedere il client significa possederne il comportamento. Ogni motore server ha la stessa politica TLS, verificata per impostazione predefinita, e lo stesso tunnel SSH, e i loro errori sono classificati allo stesso modo: una risposta del server non viene mai scambiata per una connessione persa.
Sono testati contro server reali, in container: MySQL 8.0, 8.4 e 26.7, MariaDB nella sua ultima versione (quella attuale quando aggiorno i server di prova), PostgreSQL 17 con PostGIS 3.5, SQL Server 2025, Oracle Database 26ai Free, ClickHouse 26.8, MongoDB 8.2 e Redis 7.4.
Su MySQL e MariaDB, al driver della comunità mancavano cose che si notano. Un CALL a una procedura che restituisce righe falliva con l’errore 1312, perché il driver non chiedeva mai più risultati al server; LOAD DATA LOCAL INFILE falliva con un messaggio che indicava la configurazione del server; ogni istruzione senza righe costava un secondo viaggio solo per sapere quante righe aveva modificato; gli avvisi che il server restituisce — un testo troncato a 255 caratteri, un valore fuori intervallo corretto — non ti arrivavano mai; e dei cinque modi in cui un account può autenticarsi ne parlava due, così un account con ed25519, PARSEC, PAM, LDAP o IAM di Aurora non entrava, con un errore che sembrava di password. Il mio client chiede tutto questo dal primo pacchetto: un CALL mostra le sue righe, LOAD DATA LOCAL INFILE apre un selettore e invia solo il file che scegli, le righe interessate e gli avvisi arrivano nella risposta stessa del server, e parla tutti e cinque, la password in chiaro solo via TLS.
Su PostgreSQL il driver era ben curato, e l’ho sostituito lo stesso. Ogni query dell’editor cominciava con una sonda per sapere l’id del processo del server, e fermarne una significava pg_cancel_backend da un’altra connessione, che richiede lo stesso utente o un superutente; se una transazione era ancora aperta lo si scopriva chiedendo l’ora al server due volte. I risultati arrivavano in binario, cablato nel driver, e serviva una tabella dei tipi mia per leggerli, con intervalli, array, range, tipi composti e domini scoperti. E quello che ne usavo era la sua vecchia API, marcata come deprecata in 75 punti. Il protocollo consegna tutto questo gratis: l’id del processo e una chiave di annullamento alla connessione, lo stato della transazione in ogni risposta, e ogni valore come lo stesso testo che mostra psql. Il mio client si autentica con SCRAM-SHA-256, md5 o la password in chiaro, quest’ultima solo via TLS; Kerberos e SSPI no. postgres-nio è sviluppato attivamente, e non è mai stato quello il problema: ciò che ho guadagnato scrivendo il mio è controllo, non meno manutenzione.
Da cosa è stato scritto ciascuno dei sette client, cosa parla e cosa lascia fuori è nella pagina dei driver.
SSH senza ssh
Il tunnel SSH è scritto dentro l’app, su SwiftNIO SSH 0.15.0 e swift-crypto 4.5.2. Nessuna dipendenza dall’ssh di sistema. Le chiavi decifrate non vengono mai scritte su disco.
Calíope legge da sé le chiavi private OpenSSH, accetta ed25519 ed ECDSA P-256, P-384 e P-521, verifica la chiave dell’host prima di inviare qualsiasi altra cosa e apre un canale direct-tcpip fino al database. Dal tuo lato ascolta su 127.0.0.1, su una porta scelta all’apertura del tunnel, e la connessione al database passa per quel proxy locale. Una chiave protetta da passphrase viene decifrata in memoria, e lì resta.
TLS è verificato per impostazione predefinita. Attivare SSL significa che il certificato del server viene controllato rispetto alle radici di fiducia del sistema; una CA che fornisci passa alla verifica del solo certificato (senza controllo del nome host); e saltare la verifica è una scelta esplicita, con un avviso visibile. La stessa politica (TLSBuilder) vale per MySQL, MariaDB, PostgreSQL, SQL Server, Oracle Database, MongoDB e Redis. ClickHouse, via HTTPS, offre le stesse tre scelte con una propria politica su URLSession, e con una tua CA continua a verificare il nome rispetto all’host del profilo, anche attraverso un tunnel SSH. Oracle Database, via TCPS, segue la stessa politica, salvo che con una tua CA continua a verificare il nome rispetto all’host del profilo, anche attraverso un tunnel SSH; e un profilo con un certificato client viene rifiutato.
Dentro la sandbox
Calíope gira con l’App Sandbox attiva, come richiede il Mac App Store, e Caliope.entitlements chiede esattamente questo:
com.apple.security.app-sandboxcom.apple.security.network.client— le connessioni in uscita verso i tuoi servercom.apple.security.network.server— i listener locali: il proxy del tunnel e il server MCPcom.apple.security.device.audio-input— la dettatura, che gira sul dispositivocom.apple.security.files.user-selected.read-write— i file.sqlche apri e le cartelle che scegli per i backupcom.apple.security.application-groups— il contenitore condiviso da cui leggono i widgetcom.apple.security.print— stampare l’editor SQL, il log delle query, un diagramma ER o un report- iCloud:
CloudDocuments,CloudKite l’archivio chiave-valore, per la sincronizzazione che puoi attivare
E ciò che non c’è: nessun accesso all’intero file system, nessuna eccezione alla validazione delle librerie, nessun JIT.
IA e MCP alle tue condizioni
L’assistente IA ha tre tipi di provider. Apple Intelligence passa per il framework FoundationModels di Apple, sul dispositivo, senza chiave e senza account. Ollama gira sulla tua macchina, con i modelli che ci hai installato. I provider cloud funzionano con la tua chiave. L’app decide come parlare con un provider in base alle capacità che dichiara, non al suo nome. È un assistente, non un agente.
Il server MCP, su macOS, capovolge il verso e lascia che un client IA esterno — Cursor, Claude Desktop, qualunque cosa parli MCP — interroghi Calíope sui tuoi database, entro dei limiti. È spento di fabbrica. Ascolta solo su 127.0.0.1, sulla porta 41500 a meno che tu non la cambi, e quell’indirizzo non è configurabile. Ogni richiesta ha bisogno di un token Bearer che Calíope genera (32 byte casuali) e conserva nel Portachiavi. Il client vede solo le connessioni che esponi esplicitamente, e quella lista nasce vuota. Accetta solo letture: un’istruzione per chiamata, controllata da una lista bianca di istruzioni — non da una transazione di sola lettura — che rifiuta anche FOR UPDATE e LOCK IN SHARE MODE, e i risultati sono limitati a 200 righe; la pagina MCP consiglia di esporre un utente del database senza privilegi di scrittura. Cinque strumenti, JSON-RPC 2.0 su una sola rotta POST /mcp, versione di protocollo 2025-06-18. Nessuno dei due consensi — né l’interruttore né la lista esposta — si sincronizza su un altro dispositivo né viaggia in un backup delle impostazioni. La pagina del server MCP elenca i cinque strumenti e spiega come puntarci un client.
Ciò che di proposito non fa
- Né Windows né Linux. Calíope è scritta per le piattaforme Apple e lì resta.
- Né Oracle Database oltre un client: AWR, SQL Trace e la modifica del PL/SQL restano fuori, ed è misurato solo su 26ai. I motori di oggi sono MySQL, MariaDB, Amazon Aurora, PostgreSQL, SQL Server, Oracle Database, ClickHouse, Redis, SQLite, DuckDB e MongoDB.
- Né spazi di squadra. Non c’è un mio server né account; i tuoi profili e la tua cronologia sono tuoi, e la sincronizzazione iCloud è un’opzione tra i tuoi dispositivi.
Se hai bisogno di una di queste tre cose, il confronto onesto nomina gli strumenti che la fanno bene.