Calíope app icon

Features

Every capability, verified against the source code.

Calíope ships as a single application with the capabilities below available on Mac, iPad, iPhone and Apple Vision Pro. Every entry corresponds to code that exists today — this is a catalogue, not a wish list. Use the shortcuts to jump to a category, or scroll through the full list.

This page describes Calíope 1.7, the version I am building right now. 1.6 is on the App Store for the Mac, iPad, iPhone, Apple Watch, Apple TV and Apple Vision Pro. The changelog says which version each feature landed in.

Connection & Security

Native SSH tunnel

“Your SSH tunnel, without a terminal or .ssh/config.”

Reach servers behind a bastion from within the macOS sandbox — no local ssh, no ~/.ssh/config, no permission fights.

SwiftNIO + NIOSSH. Password or private-key auth (ed25519, ECDSA P-256/P-384/P-521). OpenSSH parser and in-memory passphrase decrypt. Local proxy on 127.0.0.1 bridged via SSH direct-tcpip.

TOFU host-key verification

“Warns you if someone intercepted your tunnel — before you type anything.”

Detects a MITM against your SSH bastion without keeping a known_hosts file on disk.

Fingerprints stored in Keychain. First connection prompts for explicit confirmation; a changed fingerprint fails hard — equivalent to StrictHostKeyChecking=yes.

Strict TLS by default

“SSL that actually protects — not just a toggle.”

Turning “SSL on” means SSL verified. Self-signed certificates require a CA or an explicit opt-out with a visible warning.

Single policy: skip-verification is opt-in; a supplied CA yields no-hostname verification; otherwise full verification.

Keychain with opt-in iCloud sync

“Your passwords do not visit iCloud unless you invite them.”

You decide which credentials travel across your devices. By default, none.

Local-only mode pins credentials to WhenUnlockedThisDeviceOnly; enabling sync migrates them to AfterFirstUnlock for iCloud Keychain. Toggle is idempotent.

Optional biometric auth per profile

“Your fingerprint unlocks prod, not just your sleeping Mac.”

Add a Touch ID / Face ID gate before connecting to production servers, configurable per profile.

Built on the LocalAuthentication framework. Enabled per connection profile.

Deterministic connection pool

“A connection pool that always closes — even when something fails.”

Connections that do not leak resources or block the UI, even when switching sessions.

SwiftNIO EventLoopGroupConnectionPool, capped at 5 connections per event loop on a single-thread event-loop group. Async teardown with a safety timeout, and a clean SSH close when local binding fails.

Native prepared statements

“Bindings prepared, not string interpolation — from the root of the stack.”

The values Calíope’s tools send for you — a filter, an edited cell, an inserted row — never get concatenated into the SQL: they travel through the wire protocol, separated from the statement. What you write in the SQL editor goes as you wrote it, as in any client.

Each engine’s own prepared statement, in a client I wrote: no bindings → a plain query (COM_QUERY on MySQL and MariaDB, the simple query on PostgreSQL); with bindings → COM_STMT_PREPARE and COM_STMT_EXECUTE on MySQL and MariaDB, with the statement closed on every path where the connection survives, so the pool never leaks, and Parse, Bind and Execute on PostgreSQL, with $n placeholders. SQL Server: sp_executesql over RPC, with typed parameters. Oracle Database: typed :1 binds in the execute call. ClickHouse: typed {name:Type} parameters, sent as param_ fields of the HTTP request. Identifiers still flow through the centralized escape helper for the residual DCL/DDL cases.

Alternate host per profile

“One server, two addresses — and it tries both.”

The same server is often reached at one address from the Mac and another from the iPad. Give the profile a second address and Calíope tries it when the first does not answer, with the same port and credentials.

The destination is resolved by connectionEndpoints, never by reading the host field: the three places that open a pool receive the endpoint. Fixed order, main then alternate, with no memory of which one won — that state is exactly what cannot travel between devices. Accepts host:port for a route that publishes a different port. Ignored with an SSH tunnel, and the interface says so: there the host is resolved by the bastion, not by your device.

Environment tags

“Know which server you’re on before you run anything.”

Each connection can carry a tag with the name and color you choose — local, staging, production — and a band in its color sits above every tool, with a protection level that can ask before anything writes or refuse it outright.

One guard, written once, judges every statement before it is sent; read-only also puts the server itself in read-only mode where it knows how — SET SESSION TRANSACTION READ ONLY on MySQL and MariaDB, default_transaction_read_only at startup on PostgreSQL, readonly=2 on every ClickHouse request — while on SQL Server, Oracle, Redis and MongoDB the guard is the client alone. It protects against accidents, not attackers: that job belongs to a read-only user on the server.

SQL Editor & Productivity

Context-aware autocomplete

“The editor knows if you are in the FROM, the WHERE, or the column list.”

Write less, and make fewer mistakes, because the suggestion understands where you are inside the statement.

Suggests columns of the active table, database names, schema tokens (tables, views, functions), DML/DDL/control keywords, data types and engine-filtered SQL helper phrases.

Live lexical linter

“Unbalanced parentheses never make it to the server.”

Catches the obvious mistake before the server rejects it.

Detects unclosed comments, unclosed strings, unbalanced parentheses and open backtick identifiers. O(n) scan, no full parser.

Formatter, and a safe mode

“A DROP does not go out by accident.”

Readable formatting for your queries, and a lock that keeps an UPDATE or a DROP from reaching the server before you mean it.

The formatter capitalises keywords from the engine's own vocabulary. Safe mode, on by default and saved per profile and per editor tab, refuses to run any statement that contains ALTER, CREATE, DELETE, DROP, GRANT, TRUNCATE, UPDATE, REPLACE or RENAME — from the editor, the Terminal and the SQL Player alike. It looks for the word, not for the WHERE: an UPDATE with one is stopped too, and nothing is sent until you turn it off.

Credential redaction in logs and sync

“Sync your history, not your credentials.”

Your query log does not become a password file on iCloud.

Neutralises IDENTIFIED BY, IDENTIFIED WITH … AS, IDENTIFIED BY PASSWORD, SET PASSWORD FOR and PASSWORD(…). Idempotent redaction, applied before exporting the query log to CloudKit.

Visual query builders

“Compose queries with clicks; they come out production-ready.”

A correct SELECT … WHERE … JOIN … without memorising syntax.

Dedicated visual builders for the four most frequent shapes: SELECT, WHERE, UPDATE, and table CREATE.

Rename symbol with word boundaries

“Rename id without breaking client_id.”

Refactor identifiers safely, without wrecking similar names.

Regex with \b word boundaries and proper regex escaping. Never matches inside larger identifiers.

Quick Open palette (⌘⇧O)

“⌘⇧O and you are on the table you were looking for.”

Reach any schema object without walking down the tree.

Incremental fuzzy search across tables, views, routines and objects, with arrow-key navigation and Enter to open.

Snippets manager with per-engine seeding

“Your snippets adapt to the engine, not the other way around.”

Your SQL recipes are always at hand, filtered to the engine you are using.

Stored in snippets.json, which travels over iCloud with the general sync switch and stays on the device when it is off. Each snippet declares which engines it applies to (MySQL, MariaDB, PostgreSQL…). Connecting to a new engine seeds defaults without duplicates. Supports categorisation.

DDL and function documentation popovers

“The docs for GROUP_CONCAT open where you're typing.”

Documentation without leaving the editor or opening a browser.

Shows the DDL of the schema object under the cursor, or the entry for the function: signature, description, parameters, an example and the version it arrived in. Each engine has its own entries, SQLite and DuckDB included, and so do MongoDB operators in the Query tool. Without the mouse, ⌥⌘?.

Advanced cell editor and inline row editing

“Edit the cell, see the SQL, and decide.”

Change data quickly and preview the exact SQL that will be executed.

Spreadsheet-like editing on result sets, with a preview of the generated UPDATE or DELETE before it runs.

SQL Player — a script, step by step

“Play, pause and step through your script like a video.”

Run a migration one statement at a time and check each result before the next one goes out.

Splits the editor's script into statements and runs them one by one, by hand or on a timer, with first, previous, next and last controls; automatic playback stops at the first error. Each statement shows its status, its time and the rows it returned or changed, and lands in the query history. Safe mode applies.

SQL Terminal docked in the editor

“The mysql> prompt, without leaving the app.”

Type a statement, press Return, read the answer as text — the way the command-line client does it, next to your script.

A panel under the editor with the engine's own prompt (mysql>, postgres=#…), results as an ASCII table, “Query OK” with the rows the server says it changed, and the server's warnings underneath. Its own history with the arrow keys on the Mac and buttons on iPad, iPhone and Apple Vision Pro; every statement also goes to the session history. Safe mode applies.

Result charts

“From a result set to a chart, without exporting anything.”

Bars, lines or a pie from the rows you just got, in a panel of the editor.

The axes are picked for you — the first text column for the categories, the first numeric one for the values — and you can change them. The chart exports to PNG or PDF.

One query, two databases

“Is staging the same as production? Ask both at once.”

Run the same query against two connections and see, row by row, what differs.

Run on two databases… sends the statement to both and replaces the grid with a comparison: changed cells marked, rows present on only one side, and a filter to show only the differences. Rows are matched by position, and only when both sides return the same columns.

iPad hint bars above the keyboard

“iPad keyboard with SQL superpowers.”

Fast touch suggestions right above the on-screen keyboard.

Contextual bars for the object or function under the cursor, with quick access to “View DDL” and function parameters.

Customisable toolbar

“Your toolbar, in your order.”

Each person has their own ergonomics; DBAs reorder once and forget.

Reorder or hide button groups from a dedicated customiser sheet. Layout is persisted.

Global search and replace, across a database

“One search across every text column you have.”

Search a string in every text column of every table at once, see the matches per table and column, preview the result computed by the server, and replace in bulk inside a transaction per table.

It shows two counts, not one: collation usually ignores case and REPLACE() never does, so without that warning a bulk edit announces 300 rows and changes 100 without anything failing. The mismatch is measured with CAST(col AS BINARY) rather than a named collation. Generated, primary-key and unique columns are excluded by default — MariaDB accepts an UPDATE on a generated column, reports one affected row and changes nothing. Escaping uses |, because a backslash breaks under NO_BACKSLASH_ESCAPES.

Spatial data on a real map

“Your GEOMETRY columns stop being 25 bytes.”

Points, lines and polygons drawn on a map docked in the editor, with satellite and flat styles, clustering and a fit-to-data control. Drag a pin or a vertex and Calíope composes the statement — it shows it to you before writing anything.

The WKB on the wire is always (longitude, latitude); what changes is the text, because MySQL 8 under a geographic SRID prints latitude first and MariaDB never does. The swap lives only at the textual boundary, where the parameter has no default value: getting it wrong does not raise an error, it moves the row to another continent and the server accepts it. The SRID travels with the geometry, editing is blocked without a reliable primary key and it says why, and there is no CoreLocation anywhere.

Reports

A saved query with a declared output

“A saved query that gives the same answer twice.”

Save a query with its parameters declared and its output defined — which columns, in what order, with what titles and formats — and run it whenever you like, by hand or on a schedule. Export it to CSV, TSV, JSON, Markdown, HTML, XML, text, Excel or a paginated PDF. The report definitions travel with iCloud sync; their results and run history stay on the device that ran them.

Parameters are bound, never pasted into the query text: nothing typed into them can alter what it does, in either SQL mode. The output contract is enforced at run time — a column that stops arriving, or arrives with another type, is announced rather than silently drawn. Every run leaves a row in a history shared with backups, with its parameters, its row count and the machine that ran it. Scheduled runs open their own connection from the profile, and never promise to run with the app closed.

Three kinds of database, one seam

“The same report, against three different kinds of database.”

The same artefact and the same screen serve your production MySQL, the .sqlite file of an app, a .duckdb file and a MongoDB collection.

The report engine does not hang off the database provider: it has its own, narrower seam, with three members and nothing more. There are implementations for relational databases, for SQLite and DuckDB files you opened yourself, and for MongoDB through find and aggregate. Adding a source means implementing that protocol without touching the engine. And no source keeps state from the previous run — when one did, the second report was projected with the first one's columns: a table of empty cells, with no error and no warning.

Reports that prepare before they read

“Prepare, index and read — over a single connection, and without touching your tables.”

The reports a DBA would write as a five-step script fit into one report, without giving up the guarantee that it never touches your data.

Not every report comes out of one query: setting a session variable, building a temporary table in several passes, indexing it and reading it at the end. The whole batch runs over a single borrowed connection — with one connection per statement, the temporary table created by the first would not exist by the last. Preparation statements go through a whitelist and can only write to temporary tables belonging to their own batch, and the row ceiling applies to the final one.

Nine export formats, and a PDF that measures the page

“Nine formats, and the PDF knows where the page ends.”

The PDF you send upstairs says “Amount”, and the CSV of the same report says “Amount” — not total_eur.

CSV, TSV, JSON, Markdown, HTML, XML, plain text and XLSX — written by Calíope itself as ZIP plus XML, with no dependencies — plus a paginated PDF. What gets exported is what the output declares, not what came back from the server. And the PDF pagination is measured from the font's ascent, descent and leading rather than estimated with a constant: a constant cuts the last row of every page in half, and that only shows up once it has been printed.

Administration & Catalog

Catalogs: a navigable schema tree

“Your schema, in a tree that mirrors how you think.”

One view for the whole server catalog.

Databases → tables / views / routines / triggers / events, with lazy loading and contextual actions: DDL, columns, indexes, data import, WHERE builder.

Schema diff with ALTER generation

“Diff your schema, generate the ALTER, review before applying.”

Promote a schema from staging to prod without collecting diffs by hand.

Compares two schemas and generates the ALTER TABLE needed to bring one to the other. Column comparison runs concurrently via structured concurrency. Source of truth: INFORMATION_SCHEMA.

Local DDL audit log

“Know what DDL you ran, when, and against which server.”

Traceability of schema changes, without touching the server.

Every CREATE / ALTER / DROP / RENAME is recorded locally with timestamp and target server, in the app's local SQLite store.

Data migration between servers

“From staging to prod in three clicks — with a preview.”

Clone objects across environments without mysqldump or hand-crafted .sql files.

Dual connection (source + destination), granular selection of tables, views, routines, triggers and events, with options for REPLACE, include data, or skip foreign keys. SQL preview before execution.

Advanced object editors

“One editor per object type, not a generic .sql for everything.”

Edit routines and events properly, in an editor built for the object.

Dedicated sheets for stored routines, triggers, events, views and indexes. Each emits well-formed DDL.

Table Builder

“A table designed column by column, not typed out.”

Create a table or change an existing one — columns, types, keys, indexes, foreign keys — and read the CREATE or ALTER TABLE before it runs.

Each engine declares its own catalogue of types and options, so the builder offers what that server has, ClickHouse’s sorting key and skip indexes included. Changing a table compares against a snapshot of the original and writes the ALTER TABLE for what changed, and nothing else. Opens from Catalogs.

Table maintenance

“CHECK, REPAIR, OPTIMIZE, ANALYZE and CHECKSUM, in one button.”

Housekeeping for your tables, on MySQL, MariaDB, PostgreSQL, SQL Server, Oracle Database and ClickHouse, without memorising the commands.

Runs CHECK TABLE, REPAIR TABLE, OPTIMIZE TABLE, ANALYZE TABLE and CHECKSUM TABLE on MySQL and MariaDB, and ANALYZE plus VACUUM and REINDEX TABLE CONCURRENTLY on PostgreSQL, and UPDATE STATISTICS, DBCC CHECKTABLE and index rebuilds on SQL Server, and CHECK TABLE and OPTIMIZE (whole table or one partition) on ClickHouse, and statistics through DBMS_STATS on Oracle Database, with progress feedback.

User admin: users and privileges

“GRANTs and REVOKEs — with checkboxes.”

Manage server users without hand-writing every GRANT.

CREATE / ALTER / DROP USER, plus GRANT and REVOKE from a dedicated UI.

Index Advisor and index editor

“The indexes you have too many of, and the ones you're missing — with evidence.”

Identify redundant or missing indexes using data the server already exposes.

Advisor view that analyses index usage, paired with a dedicated editor for the index catalog.

Column profiler

“Profile the column, don't guess the data.”

Understand the quality of your data before writing the analytical query.

Statistics for one column of the result you have loaded: nulls and their share, distinct values, minimum, maximum and mean, and the ten most frequent values, with a bar chart of the top eight.

Interactive ER diagram

“The ER diagram you no longer have to draw.”

Document relationships without drawing boxes in Miro.

Automatic generation from the active schema, with foreign-key visualisation.

MongoDB

MongoDB

“Document databases, with their own vocabulary.”

Browse collections and documents, edit them as JSON, write filters and aggregation pipelines, manage indexes and check the server, its running operations and its users — without leaving the app you already use for MySQL.

Self-contained tool: nothing of MongoDB touches the relational provider layer. Documents are shown as collapsible trees with the type of every value (ObjectId, decimal128, dates, binaries), because a collection has no schema and two neighbouring documents may share no field. Extended JSON in both directions with its own parser, so field order and numeric widths survive a round trip. Reuses the connection profile, the Keychain and the native SSH tunnel. Paginated cursors that are closed when abandoned. Six tools in the navigator: MongoDB collections, MongoDB query, MongoDB indexes, MongoDB server, MongoDB commands and MongoDB profiler.

Redis

Redis

“Keys, memory and commands — not tables pretending.”

A Redis session opens seven tools of its own: the key browser, the server panel, the memory analyzer, slow commands, connected clients, the command console and the node topology. You see which prefix is eating the memory, which command went over the threshold and which client to disconnect, from the same app you use for SQL.

Its own RESP client, outside the relational provider layer. Keys are walked with SCAN, never KEYS, and no collection is read whole — a large HGETALL blocks the server just the same. In a cluster, MOVED refreshes the slot map and ASK does not; a cluster is not opened through an SSH tunnel, because it announces addresses the tunnel cannot reach, and the session says so before it opens. The console refuses what would leave state on the connection (MULTI, WATCH, SUBSCRIBE…) and blocking commands with no timeout. The slow-log threshold is in microseconds, and it is written that way.

Works Without a Server

SQLite Editor

“Two engines, one app: your remote MySQL and your local SQLite.”

Open and edit the .sqlite of an iOS app or a Python script in the same tool where you administer MySQL — with an explicit transaction before anything is written.

Self-contained layer (SQLiteConnection actor over the system C API — it goes through no server driver) with Structure · Data · Execute SQL · Pragmas: table, index and view designers, rename, search and filters, pagination with the same page size as the SQL Editor, sorting, advanced cell editor, Execute SQL with syntax highlighting, autocompletion from the file's schema and a row cap on results, Save/Revert transactions, maintenance (integrity_check, VACUUM, ANALYZE, REINDEX), editable pragmas and CSV · JSON · SQL import/export. Sandbox-safe through security-scoped bookmarks. Unencrypted databases only.

DuckDB Editor

“Analytics on your laptop: a columnar engine with no server to install.”

Open a .duckdb file, or query a Parquet, CSV or JSON where it already is, without importing anything and without a server — in the same app where you administer MySQL.

DuckDB 1.5.5 compiled into the app (local SPM package, DuckDBKit over the C API), outside the database provider like the SQLite Editor. Structure · Data · Execute SQL · Settings, with sequences, types and macros in the schema tree, SUMMARIZE, row cap and Stop on long queries, whole-database export and import, Save as… for in-memory databases, and attaching another DuckDB file read-only. Extensions are not downloaded: the four that ship inside are all there is.

File Previewer

“Reading a file shouldn't require a connection.”

Read the documentation .md, a colleague's .sql, a config .json, an exported .csv, an .rtf someone sent you or a server .log without leaving the app, without connecting, and with no risk of running anything by accident.

Read-only, one file at a time, resolved by extension: own Markdown renderer (ATX and setext, nested lists, checklists, fenced and four-space indented code, quotes, rules, GFM tables), SQL highlighter, JSON formatter, RFC 4180 CSV reader with separator detection, and an RTF reader that keeps structure and emphasis — headings, nested lists, bold, italic, underline, strikethrough, links and alignment — while typeface, sizes and colours stay Calíope's, so the text scales with Dynamic Type and reads in either theme. Everything is parsed off the main thread and reaches the view as inert data. Watches the file path with DispatchSource, so it survives atomic saves. Declared ceilings, stated in the footer: 5 MB read, 500 KB SQL highlighting, 2 MB JSON formatting, 10,000 rows and 64 CSV columns. Never opens the network — remote Markdown images show their alt text.

AI Assistant, with or without a key

Bring-Your-Own-Key. The purchase does not include AI credits — you use your own API key. This is disclosed openly on the paywall: “The assistant works with no key at all through Apple Intelligence or Ollama; cloud providers (OpenAI, Google Gemini, Anthropic Claude) require your own key, which is not included in the purchase.”

With Apple Intelligence, nothing leaves the device; with Ollama, nothing goes beyond the machine you point it at. With OpenAI, Gemini or Claude, the schema of the active database — table names, columns and foreign keys — does travel to that provider, under your own key. Rows and credentials never do. Unless you decide otherwise: the Send schema to the model switch, in the assistant’s own panel, settles it before any question and with any provider. Off, nothing of the schema is sent — not even table names — and you name the tables in your question. On macOS, Calíope can also act as an MCP server for an AI client on the same Mac: read-only, on 127.0.0.1, off by default.

Apple Intelligence and Ollama, with no key

“Two providers that cost nothing and ask for nothing.”

Apple Intelligence runs the system model on your own device: no key, no account, no cost, and your question never leaves the device. Ollama runs open models where you say — your machine, or one on your network — and Calíope talks to it at the address you write.

Apple Intelligence through FoundationModels; it is offered only where the system says it is available. Ollama over the OpenAI protocol against your own base URL, with no Authorization header, and the model list unfiltered — its names are whatever you pulled. When the schema does not fit the local window, the assistant says so in the conversation and proposes what to do.

OpenAI, Gemini and Claude providers

“AI that runs on your tokens, not on your bill.”

Use the model you already pay for, and don't depend on Calíope raising prices per token.

OpenAI (gpt-, o1, o3 and o4 models) with Bearer token. Google Gemini with API key; filtered to models exposing generateContent. Anthropic Claude (claude-*) with x-api-key and the system prompt kept in its own field (not inside messages). System prompt with the active-schema context, keeping the last three exchanges.

API-key redaction in errors and logs

“Your key never appears in a stack trace.”

If an error message escapes to a screenshot or a Slack channel, your API key does not travel with it.

Regex-based masking for sk-* (OpenAI), AIza* (Gemini), sk-ant-* (Anthropic Claude, including sk-ant-api03-…), and Bearer … in any provider error message.

Exponential backoff with Retry-After

“If OpenAI says wait, Calíope waits exactly that long.”

Rate-limit spikes don't break your session.

On 429 / 503, retries up to three times (1s / 2s / 4s), honouring the Retry-After header. Timeouts: 30 s for generation, 15 s for listing models.

Voice-to-SQL

“Speak the question; run the SQL.”

Dictate a request and have the assistant turn it into SQL — useful on iPad and in hands-busy pair-DBA sessions. Your voice never leaves the device.

Built on Apple's SpeechAnalyzer and DictationTranscriber (macOS 26 / iPadOS 26 / iOS 26 / visionOS 26): recognition runs on the device, no audio is sent to any server, and dictation works offline. The language model is fetched once, with visible progress, in the language you set in Calíope — or in any other language the system's dictation supports, picked from the capsule next to the microphone, which says which one it is listening in. Only the microphone permission is requested — on-device recognition needs no speech-recognition permission. Live partial results.

Persistent conversational assistant

“A conversation with your database, not an isolated prompt.”

Ask “now with a LEFT JOIN” and it knows which query you meant.

Keeps context of the active schema plus the last few exchanges, per conversation.

An MCP server for an AI client on your Mac

“Cursor or Claude Desktop can ask your database — read-only.”

An AI client on the same Mac can list databases, describe tables and run read-only queries against the connections you choose to expose.

JSON-RPC 2.0 over HTTP, listening only on 127.0.0.1, on port 41500 unless you change it. macOS only, off by default, and it answers only while Calíope is open. Five tools, documented with the descriptions the client receives on their own page.

Backup, Import & Sync

Backup engine with opt-in credentials

“Backups with native gzip — and no accidentally exported passwords.”

Compact, safe-by-default dumps — nobody exports password hashes by accident.

Generates .sql with options for drop-before, include data, include users, include user credentials (opt-in, default off), and native gzip compression. CREATE USER / ALTER USER / GRANT are neutralised when credentials are excluded. Progress events with ETA.

Scheduled backups with retention

“Backups that don't rely on you remembering.”

Your Mac takes the backup on time, even if it was asleep, and doesn't fill up your disk.

Daily, weekly, weekday, monthly or every-N-hours schedules. Uses security-scoped destination bookmarks to work inside the sandbox. Handles missed schedules across app restarts, nanosecond-suffixed filenames to avoid collisions, retention purge, and success/error/skip notifications.

CSV / JSON / XLSX import

“From a spreadsheet to a table in three clicks.”

Import real-world tabular files — not just the happy-path CSV.

RFC 4180-style CSV (escaped quotes, fields with commas), JSON (array of objects) and streaming XLSX. Three modes — Insert, Skip duplicates and Replace duplicates — offered where the engine has them: all three on MySQL and MariaDB, the first two on PostgreSQL, and Insert only on SQL Server, Oracle Database and ClickHouse.

Persistent local query log

“The command you ran on Tuesday, in two seconds.”

Search thousands of past queries by SQL text or date.

Local SQLite store in Application Support with tables for executed queries and the DDL audit log, indexed by query text (asc) and date (desc).

iCloud query-log sync (opt-in, redacted)

“Your SQL history, in your iCloud, without your credentials.”

Search your Mac's history from your iPad — with credentials stripped out.

CloudKit container iCloud.org.caliope.caliope, batches of 400 records, configurable retention (default 90 days). Applies credential redaction before uploading. Verifies iCloud account status before syncing.

Per-section sync toggles

“You decide what goes to iCloud.”

Sync only what you care about — not all or nothing.

Beside the general iCloud switch, independent ones for what is copied to your iCloud: in Settings, iCloud Keychain, the application error log and the system messages; the query log from its own tool, and the AI Assistant conversations from their history panel.

Dumps of many gigabytes

“722 MB dumped with 68 MB of memory.”

Backup and restore no longer depend on how much RAM the machine has. A 722 MB dump with 4 million rows peaks at 68 MB; restoring it takes 19 seconds using 14 MB. Cancelling actually stops the dump instead of letting it run to the end.

The engine orchestrates and the provider writes SQL: adding an engine to backup means implementing BackupDataSource and nothing else — the test harness implements it in memory with SQLite and Postgres dialects without touching the engine. Restore pulls one statement at a time instead of being pushed, because a buffered stream drops statements in silence and finishes announcing success. Reading uses read(2) and not a mapped file: the same splitting measured +201 MB resident with FileHandle and 1.1 MB this way.

A backup of your own settings

“Before touching iCloud, there is a copy.”

Export and import everything Calíope keeps outside the device — profiles, groups, preferences — with scheduled copies to the iCloud container and local restore points taken automatically before anything risky: enabling or disabling sync, erasing, importing.

It exists because of a measured incident: turning sync on for an iPad replaced a 16 470-byte connections.json with 28 profiles by a 514-byte one holding a sample profile. Secrets are opt-in and always encrypted (AES-GCM, PBKDF2-SHA256 with 210 000 iterations, salt and cost written into the file). Whatever is left out is written into the copy with its reason — a copy that hides its omissions is the one that makes you believe you can restore everything. Restoring merges; a backup never deletes.

Every Apple screen

Calíope on your iPhone

“The whole client, without the Mac in front of you.”

The same Calíope, laid out for the phone — the whole client, not a viewer. It connects to your servers and runs your queries, with the SQL editor, the schema browser, the dashboard, the ER diagram and the reports all there; and your connection profiles, saved snippets, query history and assistant conversations are already waiting, carried over by your own iCloud. Face ID to unlock, five languages, and a demo mode to look around before you connect anything. It installs from the same App Store page as the Mac and the iPad, and brings the same two widgets to the Home Screen: the metrics of your pinned server, also on the Lock Screen, and the health of the whole fleet.

It is the iOS binary, and it is the same code as the iPad: not one tool is removed, and there is no device check anywhere in the tree — what changes is the layout, not the feature list. Connection profiles are merged into the shared iCloud file rather than replacing it, so the fields a narrower screen never puts on show — SSH tunnel, certificates, character set — are preserved untouched. Without iCloud it names the closed switch, instead of showing an empty screen and letting you assume all is well.

Calíope on your Apple Watch

“What your servers did, without taking the phone out.”

Calíope on the wrist, arriving with Calíope on the iPhone and covered by the same purchase, with nothing to buy separately. It shows the system messages Calíope publishes: seventeen kinds in seven groups, covering backups and reports that finished or failed, queries that ran long, SSH tunnels that dropped and came back, iCloud sync that failed, and servers close to your thresholds. Grouped by day, with optional notifications on a switch of their own, and a demo mode that shows you the empty screens too.

Messages travel as an identifier plus their raw figures, never as a finished sentence: the watch is set to a different language from the Mac more often than not, so the sentence is written at the wrist. The cadence you choose is a minimum and not a promise — with the app closed, watchOS decides when to wake it — and the app says so at the top of its own settings screen instead of in grey at the bottom. The watermark is the last message delivered and not the wall clock, because wake-ups get skipped and asking «anything in the last fifteen minutes?» discards the rest without failing. It only reads: it opens no connection to any server of yours.

Calíope on your Apple TV

“The fleet's health, read from across the room.”

A wall dashboard for the servers you run on MySQL, MariaDB, PostgreSQL, SQL Server, Oracle Database and ClickHouse: one tile each, with its state — Healthy, Warning, Critical, Unreachable or No data — and, when something is wrong, what is wrong. Uptime, connections, running threads, queries per second, cache hit rate, longest running query and replica lag. Two tabs, because a television is not a device you navigate, and a demo fleet of eight servers to look around first. Put Calíope in the top row of the Home Screen and the band above it shows your published servers, the most urgent first, then the demo videos from this site; choosing a card opens that server.

Staleness is worked out by the reader, derived from the cadence Calíope declares: whoever published does not know that they stopped publishing, so a Mac switched off on Friday would otherwise leave the dashboard green all weekend. State is never shown by colour alone, and the thresholds are Calíope's — the TV paints, it does not judge. Apple TV has neither iCloud Drive nor iCloud Keychain, so «it only reads» is held up by the platform and not by a promise.

Calíope on Apple Vision Pro

“The whole client, hanging in the room.”

From 1.6, Calíope is a native visionOS app on Apple Vision Pro: the SQL editor, the schema browser, the ER diagram, backups, reports, the query builder — every tool, with nothing removed. It connects to your servers and it writes. The tool navigator and your open tabs live in ornaments outside the glass, every control is sized for your gaze and lights up when you look at it, and you can open several windows and leave each one where you want it in the room. The widgets hang on a wall or sit on a table. It comes from the same App Store page and the same purchase as the Mac and the iPad.

It is the same app as on the iPad, built for visionOS rather than run in compatibility mode: the system glass instead of opaque backgrounds, toolbars as ornaments, 60-point targets with the gaze highlight, sheets sized for the window, and Optic ID where the iPad says Face ID. I had a native panel before and did not ship it, because it did less than the iPad app; this one does everything the iPad does. Until 1.6, Calíope ran on Apple Vision Pro as the iPad app, in compatibility mode.

Monitoring, Diagnostics & Replication

Monitoring engine with your own storage

“Metrics of your servers, stored on a server of yours.”

Historical monitoring without installing Prometheus.

A dedicated collector writes snapshots to a storage server of your choice, provisioning tables for samples (CPU, memory, connections, QPS) and events (threshold breaches, replication lag). Automatic retention.

Interactive Visual EXPLAIN

“Your query plan as a diagram that breathes.”

Spot the full scan that's killing your query without reading JSON or XML by hand.

Asks each engine for its own plan without running the query — EXPLAIN FORMAT=JSON on MySQL and MariaDB, EXPLAIN (FORMAT JSON) on PostgreSQL, SHOWPLAN_XML on SQL Server, EXPLAIN PLAN on Oracle Database, EXPLAIN PLAN json = 1 on ClickHouse — and draws it as a tree. Colour-coded by access type: full scan, range / index merge, optimised, sort, join. Tooltips with access_type, estimated rows and timing. Zoom with the wheel, with a trackpad pinch or with the toolbar buttons — the scale is always on screen, and ⌘+ / ⌘− / ⌘0 do the same without a trackpad. Pan by dragging.

Query profiler

“See where you're losing the milliseconds.”

Locate which phase of the query is taking the time.

On MySQL and MariaDB, built on SHOW PROFILE; on ClickHouse, which has none, it reads the query’s row in system.query_log. Table plus bar chart per phase (starting, Sending data, and so on) with millisecond timing. On PostgreSQL, SQL Server and Oracle Database the button is not there.

Slow query log, on whichever engine you are on

“What your server already wrote down about the queries that took too long.”

You read what the server recorded — from every client that connects to it, not only from Calíope — and from the same screen you turn the log on, move the threshold and empty it. One button sends the query to the editor, and the profiler is right there.

Each engine in its own vocabulary. MySQL and MariaDB: the entries come from mysql.slow_log when the server writes to a table, and the per-statement summary from performance_schema; the threshold is long_query_time. PostgreSQL: pg_stat_statements, aggregated by statement shape rather than one row per execution, and the threshold goes in with ALTER SYSTEM plus pg_reload_conf() — one that came from the command line the server was started with is declared unchangeable from here instead of failing quietly. Oracle Database: the cursor cache in V$SQL, with the threshold applied when reading, since Oracle keeps no slow log; AWR stays out, as it needs a paid pack. SQL Server: the plan cache in sys.dm_exec_query_stats, aggregated by statement — it keeps no slow log either, and nothing has to be switched on to read it. ClickHouse: system.query_log, with its threshold in milliseconds and the log flushed before it is read. Redis: a tool of its own, Slow commands, with the threshold in microseconds. MongoDB: a tool of its own, because the profiler is per database. An empty list is never the answer: if the log goes to a file on the server's machine, if performance_schema is off, or if the extension is not created in that database, that exact reason is on screen. On Aurora the settings are read-only — they live in the cluster's parameter group. No charts, and nothing is copied into Calíope: you see the window the server keeps, on the server's own clock.

Process list, with guided KILL

“A KILL for the query that hung your prod.”

Terminate a runaway query without opening a terminal.

SHOW FULL PROCESSLIST with columns for id, user, host, database, command, time, state and info. Actions for KILL QUERY and KILL CONNECTION. On PostgreSQL the list comes from pg_stat_activity and stops with pg_cancel_backend or pg_terminate_backend; on SQL Server, from sys.dm_exec_sessions and sys.dm_exec_requests, and stops with KILL; on Oracle Database, from V$SESSION, each session named by SID,SERIAL#, and it stops with ALTER SYSTEM CANCEL SQL or ALTER SYSTEM KILL SESSION; on ClickHouse, from system.processes, where what runs is a query and not a connection, so there is one action, KILL QUERY.

Replication monitor (old and new vocabulary)

“Old and new replicas, in the same panel.”

See replica lag without fighting the legacy vs. new vocabulary.

SHOW REPLICA STATUS on MySQL 8.0.22+ and MariaDB 10.5.1+, with automatic fallback to SHOW SLAVE STATUS on earlier versions. On ClickHouse, where replication is per table, it shows the replicated tables, Keeper, the worst lag in seconds and the queue in entries. Metrics: IO/SQL running, seconds behind source, last errors with timestamp, GTID sets, log positions. Configurable auto-refresh.

Replication topology

“A replica can say zero seconds while it runs hours behind. Here you see it.”

You see the whole group at once, and you stop trusting a “0 seconds” that really means “I have just reconnected”.

You declare which machine is the primary and which are the replicas. Nothing is auto-detected: SHOW REPLICA HOSTS only sees what is connected at that instant, so a detected group would change on its own and “this replica is gone” would be indistinguishable from “this replica is down”. That query is used to contradict an incoherent configuration, never to reconfigure it. Whether a replica reads from another machine is decided by server_id, never by host name — behind Docker, NAT, a VPN or a tunnel, comparing strings gives a permanent and false warning. A stopped IO thread is critical even when the lag reads zero, and next to it goes the GTID drift, counted per origin rather than subtracted. A member that does not answer does not take the others down: “7 of 9” is a normal reading, and the missing ones are named. It only reads — it never operates on the group. The diagram carries a table as its accessible alternative, and no state is told apart by colour alone.

Binlog viewer with filters and PURGE

“Your binlog, filterable and prunable — from the app.”

Audit which events your statements produced without dropping to mysqlbinlog.

SHOW BINLOG EVENTS with categorisation into DDL / DML / System, text search, and a configurable row limit (default 300). Supports encrypted binlogs (MySQL 8.0.14+). PURGE BINARY LOGS TO with explicit confirmation. MySQL and MariaDB only: the other engines keep no binary log, and the tool is not offered there.

Dashboard, Server information and Server health monitor

“The pulse of your server, in one view.”

Consolidate server health without opening five clients.

Multi-tab Server information (global & session variables, global & session status, HDD usage), a Dashboard with live charts, and a Server health monitor.

Live benchmark

“Two queries on the scale; one wins.”

Choose between two queries with evidence, not intuition.

Compares execution times of query variants side by side.

Local alerts and notifications

“Your Mac tells you when the replica falls behind.”

The system pings you — you don't have to keep staring at the app.

Threshold alerts on CPU, memory, connections and replication lag. Native macOS/iOS notifications.

SQL alerts

“Your own rule, written in SQL, watched for you.”

Write a query that returns one value, choose an operator and a threshold, and Calíope runs it again on the interval you set and marks the rule when it crosses the line.

Operators >, <, = and <>, compared as exact decimals rather than doubles, and = and <> on text too. Six states, not a yes or no: not measured yet, OK, alert, no rows, failed with the server’s own message, and refused because it writes under a protected environment tag. The rules travel in iCloud with the general switch; the measurements stay in the session, so an old reading is never shown as current.

Everything running, in one place

“What is running no longer disappears when you switch tabs.”

Queries, backups, migrations and scheduled jobs are all registered in one place, with elapsed time, destination and a Stop that actually stops. Visible from the sidebar footer, from the tab that is working and from the server switcher.

Operations enrol themselves — nothing polls anyone else's flags, because a register that guesses ends up lying in both directions. Tasks (which start and end) and modes (which stay on until someone turns them off) are different types, so a mode carries no progress bar or stopwatch. A batch survives its view being destroyed: the controller lives in a store keyed by tab, not in the view's state. Threshold of 0.8 s before anything appears — a 40 ms query is not a process.

Errors that explain themselves — and your phone can read them

“A failure with a cause, a suggestion and a record.”

When something goes wrong, Calíope says what happened, suggests what to check and links to the matching help topic. It all lands in a log with its date and device, which you can read from the phone anywhere.

No error code names an engine: the native code table lives with its provider, so adding one is implementing a protocol. The native number is read from the typed packet, not scraped from the message — the old driver did not print it, so a credentials failure used to be classified as a connection failure and sent you to check the port. On the phone it is read-only: pruning and deleting stay on the desktop. And «no errors» is an assertion — six different reasons for an empty screen are told apart, because giving the good news when the channel is simply closed is its own kind of lie.

Native Widgets

macOS desktop widget

“Server status, glanceable, on your desktop.”

See the pulse of your server without opening Calíope.

Small, Medium, Large and ExtraLarge families. Snapshots read from a shared app group with file coordination for safe concurrent reads. Payloads larger than a safe threshold are rejected (DoS protection).

iPhone and iPad Home Screen and Lock Screen widgets

“Your server on the Lock Screen.”

Server metrics on the Lock Screen of your iPhone or iPad — seconds away.

Seven families on iPad — Small, Medium, Large, ExtraLarge, plus accessory Rectangular, Circular and Inline — and six on iPhone, which has no ExtraLarge.

Widgets on the wall, in Apple Vision Pro

“Your server's pulse, hanging next to the window.”

The same widget, placed on a wall of the room: the metrics of your pinned server, where you look up and see them.

Small, Medium, Large and ExtraLarge, the Mac's four: visionOS has no Lock Screen. Glass texture, so the wall shows through, and set into the wall or standing out from it, your choice when you place it.

Fleet health widget

“Every server you watch, and which one is worst.”

A second widget that looks at the whole fleet instead of one server: how many servers you watch and how the worst one is doing, on the Mac desktop, on the Home Screen of iPhone and iPad, and on a wall in Apple Vision Pro.

Small, Medium and Large families, the same on the Mac, on iOS and on visionOS. It reads what the server health monitor measured on that device, through the shared app group; the extension queries nothing on its own. No ExtraLarge and no Lock Screen families, on purpose.

Deep-linking to the pinned profile

“Tap the widget → the right server's dashboard, in one move.”

One tap and you're on the correct server's dashboard.

Widget URL caliope://server/<uuid> when a profile is bound; falls back to caliope:// otherwise.

AppIntent-based selection

“One widget per server — edited like a weather widget.”

Pin a different widget to each server — configured in seconds.

Configurable via the system's widget-edit UI through an AppIntentConfiguration. No code required from the user.

Background refresh with system budget

“Refreshes when it matters; sleeps when it doesn't.”

The widget doesn't drain your battery and still shows fresh data.

Timeline policy hands control to WidgetKit, respecting the system's refresh budget. Falls back to the latest snapshot when no fresh data is available.

System Integrations

Siri and App Intents

“A SELECT COUNT(*) from Siri, without opening Calíope.”

Run a query or list databases from Shortcuts, without opening the app.

Registered intents: connect to server, execute query (returns TSV with headers), list databases, open workspace tab. Backed by an internal bridge exposing session and database managers to AppIntents.

macOS menus and .sql file handling

“Knows how to open from Spotlight with a .sql — like any native app.”

Behaves like a real Mac app — not a Windows or Electron port.

Full menu bar: About, Open SQL file, Recent files, Quick Open, tab navigation, Help, What's New, Privacy Policy, Support. Handles .sql file opens via NotificationCenter.

Menu-bar status item

“A menu-bar icon: you know if you're connected without switching windows.”

Connection context at a glance, without bringing the app to the front.

Menu-bar icon reflecting connection state and active profile.

TipKit onboarding

“Discover what you need, when you need it.”

Learn about features at the moment they're relevant.

Contextual tips across the tools — Quick Open, the WHERE builder, Data import, Visual EXPLAIN and the schema tree among them —, one per tool per visit and in order, so they never pile up.

iCloud continuity, iPad gestures and trackpad

“The SQL you write on the Mac is waiting on the iPad — even with the Mac powered off.”

On iPad with a Magic Keyboard, work as you would on the Mac.

Optional iCloud sync carries your connections, editor contents and preferences between devices — no proximity or Bluetooth required. Native pointer and keyboard handling on iPad. Gestures: pinch to scale the font in the editor and in the results grid, pinch to zoom a cell image, swipe on result rows, long press for context menus, pan and zoom in ER diagrams and Visual EXPLAIN, draggable panel dividers. Split View.

Screenshot mode

“Docs-ready screenshots — not amateur captures.”

Take documentation-ready screenshots with a consistent look.

Cmd+Opt+P on macOS produces PNGs styled for documentation and marketing.

In-app “What's New”

“New things, inside the app — not in a changelog.”

Learn what's new without reading the App Store's release notes.

Per-version highlights, with local “already seen” state.

Five-language UI (Spanish, English, French, German, Italian)

“Calíope speaks your language — Spanish, English, French, German or Italian.”

An app designed in Spanish first, so it doesn't feel like a machine translation.

Full en, es, fr, de and it resource bundles. The language is the one you choose for Calíope in the system settings, per app, and the widgets follow it. English fallback.

Privacy, Sandbox & Compliance

Active App Store sandbox

“Sandbox on — does what it says, and nothing more.”

Calíope cannot access anything outside its declared entitlements. The system enforces it.

App sandbox enabled with a narrow entitlements set: network client and server (for the SSH proxy), audio input (voice-to-SQL), user-selected files (documents), app groups (for widgets), printing, and iCloud (CloudKit, Cloud Documents and the key-value store).

Data-erasure service

“One button, and nothing is left behind.”

A button to leave the machine clean before you return or sell it.

On-demand deletion of everything Calíope keeps, in the six places listed under “Erase everything” below.

What the AI costs, said before you pay

“Honest pricing — which assistant needs a key, stated at purchase.”

You know exactly what the purchase pays for and what it doesn't.

The paywall says that Apple Intelligence and Ollama need no key and that OpenAI, Gemini and Claude need your own, which the purchase does not include, next to the purchase terms: one charge, no renewals, restorable on every device.

One-time purchase with a 60-day trial

“Sixty free days, no tricks.”

Try Calíope for sixty days at no cost; if you keep it, you pay once.

Non-consumable StoreKit 2 product with a 60-day free trial as a zero-price non-consumable (App Review Guideline 3.1.1). Verification via StoreKit 2's AppTransaction.shared and Transaction.latest(for:). Restore via AppStore.sync(). Price always presented from product.displayPrice.

Erase everything, and be told what happened

“Six places, one report, no silent failures.”

The erase button reaches local files, the Keychain, the iCloud Drive container, the key-value store, CloudKit and the widget's data — and publishes a tombstone so your other devices erase too instead of re-uploading everything.

A remote erase does not consult the sync switch: the switch says whether things go up from now on, not whether something is already up there, and whoever turned it on, uploaded and turned it off is exactly the case a privacy erase cannot leave out. The propagation is asymmetric so it cannot loop, and the comparison is > rather than != so an old tombstone republished by a sleeping device does not trigger a second erase. The report has one line per channel with its count and its failure — the previous version was written with silent try? and always ended in «everything was deleted successfully», a sentence that could not be false even with CloudKit down.

Ready to try Calíope?

Every capability on this page ships with the one-time purchase. Sixty days free, then buy once and keep it forever.

Try free for 60 days →