SCHEMAXIS · Declared work. Results you can check.Documentation ↗ · Contact
schemaxis/Agent’s Hands

Documentation / sqlite.md
Core 11629ae · View or edit Markdown on GitHub ↗

SQLite relational summaries

Use schemaxis.sqlite/1 with operation: summarise to turn captured typed JSON tables into a fresh relational database and an exact grouped report. Declare primary/foreign keys, optionally join a base table to one parent, filter an integer column by an inclusive minimum, and group rows to count and sum integer amounts. The qualified native application is the SQLite 3.54.1 CLI, released 16 October 2026 on Linux x64 (POSIX process/resource isolation). Python 3.10+ on the host needs only the standard library; discovery and planning do not import a native application or execute SQL.

Start with a report#

Open regional sales, replace both tables[*].source placeholders with absolute paths to departments and sales, and configure the absolute sqlite3 executable with schemaxis configure or pass --sqlite when running.

schemaxis plan sales.json
schemaxis run sales.json --sqlite /absolute/path/sqlite3 --output-directory fresh-report
schemaxis verify fresh-report

The source format is a JSON array of row objects. Every row contains exactly the declared column names. Example: [{"id": 1, "region": "North"}]. Duplicate JSON object keys, floats and booleans in INTEGER columns are errors. The source is a regular local .json file (at most 1 MiB); file symlinks and network resources are excluded. Captured source bytes are immutable evidence and remain sufficient for verification after the original source changes or disappears.

The example imports departments before sales, links sales.department to departments.id, groups by departments.region and sums sales.amount. Its literal output rows are [null,1,null], ["",1,0], ["North",3,300], and ["South",1,-30]. The sales row with null department is omitted by the inner join. The changed threshold keeps IDs at least 3, reducing North to one row totalling 200. The empty report publishes headers and zero rows. The single-table report groups the nullable integer department key without a join. A non-key join fails before execution. Studio includes editable sales and single-table starters and nested field Help.

Types, keys and relational meaning#

Declare 1–4 tables, each with 1–12 columns and 0–2048 rows. Identifiers use distinct lower-case ASCII letters, digits and underscores, beginning with a letter, at most 40 characters. SQLite internal identifiers are excluded. INTEGER means an actual JSON integer in ±1000000000; TEXT means at most 256 printable ASCII characters, excluding the reserved CSV null token \N. There is no float, decimal, date, binary, locale or unit conversion. SQL literals and identifiers are generated and quoted from these validated declarations; authored SQL and expressions are never accepted.

nullable defaults to false. Actual JSON null is the only missing value. Empty strings, zero and text case remain distinct. Each table names one nonnullable unique primary key. Foreign keys refer to an earlier table's primary key and must have the same type. Every nonnull foreign key must match a parent even when its row would later be filtered out. A nullable foreign key may be null.

from selects the base table. Optional join must exactly follow one declared base foreign key to a parent primary key. This is an inner join: null local keys produce no joined row; unique parent keys prevent multiplication. Omit join for single-table reporting. Optional where keeps values greater than or equal to minimum; null values fail the filter. Count and sum occur after join/filter.

groupBy lists 1–3 distinct qualified table.column names. Binary case-sensitive ascending order places null before other values; numeric keys sort numerically. Output names g0, g1, g2 follow that list, then row_count and total. sum must select INTEGER: null amounts are ignored, an all-null group total is null, and count includes all surviving rows. Empty results have zero groups. Integer totals remain exact; the oracle rejects any total outside ±2^53 (the row and cell caps currently impose a smaller bound).

Outputs and workflow handoffs#

Publications have stable order: 0 summary.sqlite (fresh STRICT database), 1 summary.json (columns and typed rows), 2 summary.csv, 3 schema.sql. CSV encodes null as \N, with empty strings preserved as empty cells; JSON and the database preserve integer/text/null types. No precision or units are inferred. The database contains all imported rows, including rows dropped by the report filter or inner join. It is suitable for independent read-only inspection.

Normal workflow execution, shared references, closed expressions and finite studies are supported. A downstream numeric field can use a verified JSON result, for example {"$value":"report","artifact":1,"path":"/rows/2/2"}; row positions are meaningful only for the declared deterministic grouping/order. Match units and nullability explicitly. The adaptor does not accept an arbitrary existing database or infer that another adaptor's table format is compatible. Source byte hashes participate in workflow reuse: unchanged inputs reuse, changed bytes at the same path create a new verified attempt. Schema evidence uses the framework's shared schema store automatically.

Verification and recovery#

Execution uses isolated owned CLI processes for version, import and read-only query. Trusted generated SQL, command launchers, native input hashes, submissions, stdout/stderr, captures and exact publication membership are retained. Startup configuration is disabled with -init /dev/null, a minimal environment and safe mode; extensions and auxiliary file functions are excluded. Fresh directories prevent existing database mutation. Limits include a total timeout, native CPU 30 s, 512 MiB address space, 16 MiB file cap, and bounded input/output reads. Cancellation terminates the owned process group and leaves failed evidence.

Verification independently reopens the database with Python's standard library in read-only immutable mode; compares the exact table schema, every typed row, object membership, integrity and foreign keys; and compares raw CLI query JSON against a literal nested-loop Python join/filter/group oracle. JSON/CSV outputs must match that oracle exactly. Successful CLI exit or a database file alone is insufficient. This is bounded verification, not qualification of all SQL features.

INVALID_TABLE_IDENTIFIER asks for unique permitted identifiers; INVALID_TABLE_KEY asks for a nonnullable unique primary key and an earlier same-type parent; INVALID_TABLE_QUERY asks for qualified active columns and the exact declared FK join; INVALID_TABLE_SOURCE asks for a bounded local regular JSON file; INVALID_TABLE_DATA identifies type, null, column or key problems. Correct inputs and retry in a fresh output directory. INTERPRETER_NOT_FOUND requires an absolute CLI executable; UNSUPPORTED_NATIVE_VERSION requires requalification before using another version. VERIFICATION_FAILED means retain the evidence and investigate; do not relabel the run as verified.

No arbitrary SQL, scripts, extension loading, triggers, views, left/many-to-many joins, existing database editing, network, decimals, Unicode text, live inspection, MPI or interactive reverse editing is supported.

Public API and maintenance#

The native mapping uses official CLI startup/safe mode, STRICT tables, SELECT, COUNT/SUM, foreign keys and PRAGMA checks. Latest stable was checked on the official download page and 3.54.1 release log. Run tools/qualify_sqlite.py for native baseline/variant/empty/single-table, hostile tamper, lifecycle and workflow checks. Source-bound qualification must be refreshed after shared implementation or generated-reference changes. See the completion review and the generated operation reference.