This page describes Calíope 1.5, the version we are building right now. 1.4 is on the App Store for iPad, iPhone, Apple Watch, Apple TV and Apple Vision Pro, and on the Mac the store serves 1.3 while 1.4 is in App Review. The changelog says which version each feature landed in.
Adds an “Open in Calíope” button to every topic. It only works with the app installed.
Open and query local file-based DuckDB databases, without a server.
Where it is: Workspace › Tools › DuckDB Editor
The DuckDB Editor is a standalone tool for local .duckdb files, with the same layout as the SQLite Editor: Structure, Data, Run SQL and Settings, and it works with no connection to any server.
It can also open an in-memory database — no file — from Query data file…, to work on a CSV, JSON or Parquet file without creating anything on disk.
What Calíope doesn't do with DuckDB. It doesn't download extensions — INSTALL, LOAD and UPDATE EXTENSIONS are rejected before they touch the engine — only the four that ship with the app are there. For the same reason, there are no remote-access secrets (CREATE SECRET), and you can't ATTACH a SQLite or Postgres file, which need an extension that isn't linked in. The engine's configuration is closed once it opens: no SET other than threads/memory_limit from Settings works, and not even those over raw SQL. And IMPORT DATABASE and COPY FROM DATABASE don't work either: under the hood they change a configuration option that the same rule keeps locked.
Open an existing .duckdb file or create a new one.
Where it is: Archivo
Use Open… to pick an existing .duckdb file, or New database… to create an empty one. Recent files appear on the initial screen. A Read-only badge appears when a file can't be modified.
If the file is outside Calíope's own folder, the first time you open it you're asked for access to its folder: DuckDB needs to write a .wal file next to the .duckdb one, and the app's sandbox only allows that inside a folder the user has chosen. It's remembered the next time you open a file from the same folder. No DuckDB file at hand? On the empty state, Download the sample database opens the page on the website where the public sample lives —a small shop with 50,000 orders, made with Calíope. The app downloads nothing: it opens the page and you decide.
Browse tables, views and indexes, and create them.
The Structure section shows the schema tree with each object's columns and DDL. DuckDB has no triggers, so the tree shows tables, views, indexes, sequences, types, macros and table macros. Sequences, types and macros are created from Run SQL —CREATE SEQUENCE, CREATE TYPE, CREATE MACRO, CREATE MACRO … AS TABLE—; here you can see and drop them. If the file has more than one schema, each group is prefixed with its schema name, and an object's comment (COMMENT ON) shows on hover. Use New to create tables, indexes or views, Add column or Rename table on the selected table, and Delete to remove an object.
Views created by Query data file… carry a different icon — a paperclip — and their tooltip shows the source file's path.
Attach database… opens another DuckDB database next to the current one; its contents show up in the tree prefixed with the database name, and you query them as database.schema.table. It is always read-only —writing to it would mean creating its .wal file alongside, which the sandbox does not allow— and Detach removes it. A SQLite file cannot be attached here: they are different engines, and that is what the SQLite Editor is for.
The Data section shows a table's rows in pages, with the count and the arrows on the right of the bar. How many rows fit on a page is set in Preferences › Text Editor › Results › Rows per page — Settings, on iPad. Sort by tapping a column header, narrow it down column by column with Filters, or type in the search field to look across all of them at once.
Editing a cell
macOS: double-click it. iPad: a single tap. Return confirms; Esc cancels.
Adding and deleting rows
Add row opens a form with one line per column. Unlike SQLite, DuckDB doesn't auto-assign the whole primary key: every required column needs its own value, the key included. To delete, select the row by its number and use Delete row.
None of this touches the file until you press Save changes: what you edit stays in a pending transaction that Revert changes undoes entirely.
Syntax highlighting and autocomplete, with a row cap and a Stop button.
The Run SQL section uses the same text field and results grid as the server SQL Editor, over the open file and with no connection involved.
The text is syntax-highlighted. Press Run, or ⌘↩, to run the whole script; what's drawn is the result of the last statement that returned rows. A large SELECT isn't brought in whole: it's cut at Preferences › Text Editor › Results › Row cap — the same cap the SQL Editor uses — and the grid says how many of how many it brought.
While a query is running, a Stop button interrupts it for real: the engine cuts it off mid-way, it doesn't wait for it to finish.
INSTALL and LOAD are rejected: Calíope doesn't download DuckDB extensions, so a query that needs one doesn't run, with the reason spelled out in the message.
Whatever you write to the file stays pending, just like an edit in Data: it doesn't touch the file until Save changes.
Edits are grouped into a pending transaction, just like in the SQLite Editor. An amber dot marks unsaved changes. Use Save changes to commit them or Revert changes to discard them. Closing with pending changes asks for confirmation.
DuckDB first writes to a .wal file next to the .duckdb one; flushing it into the main file (CHECKPOINT) is asynchronous, so the .wal can take a few seconds to disappear after saving and closing — the data is already safe, even while that side file is still there for a moment.
From Import / Export you can import a CSV file into a new table of text columns, export a table to CSV or JSON, or export the whole database as a SQL dump (schema and data).
This is different from Query data file…: here the CSV is copied into the .duckdb file as a new table; there the file stays where it is and is only queried through a view.
With DuckDB the CSV is read by the engine itself (COPY … AUTO_DETECT), so every column comes in with its own type rather than as text. And Whole database dumps the entire database to a folder you pick —as CSV or Parquet, with the schema beside it— or reads into the open database what another export left behind. If the database is in memory, Save as… writes it whole to a .duckdb file and keeps working on that file.
All three require no unsaved changes: the engine will not run them inside an open transaction.
Query a CSV, JSON or Parquet file as if it were a table, without copying it.
The Query data file… button creates, for each file you pick, a view over it — read_csv_auto, read_json_auto or read_parquet, by extension: the file stays where it is and is read on the fly every time the view is queried, without copying its data into the database.
The view's name comes from the file's name, without its extension; if two files would give the same name, the second one gets _2, the third _3, and so on. In Structure, these views carry a different icon — a paperclip — and their tooltip shows the source file's path.
If no database is open, the button first opens an in-memory database: there's no .duckdb file on disk, so Save as… — which doesn't do anything yet — is the only way not to lose the work when closing. That in-memory database need not be lost: Save as… writes it whole to a .duckdb file and the editor carries on with that file.
Keywords: csv, json, parquet, query, view, attach, in memory