Chapter · Connect your data

Every source.
One front door.

One call registers a source, infers a typed schema, and pins its revision into every plan that touches it. Files and SQLite run in-process — no key, nothing leaves. Live databases connect through the engine — directly, over each database's own wire protocol: credentials encrypted, no data copied.

const sales = await sqai.connect("./data/sales.csv", { name: "sales" })

→ row_count 12 · schema_revision e4938027… · status ready

typed · hash-pinned · read-only

IIThe type cases

Two trays. Twenty-six drawers.

Every drawer opens to the same contract: how it connects, what it needs, what leaves. Pull one.

In-processno key · no daemon · no network

CSV
case
file
connect
"./data/sales.csv"
auth
None. SQAI reads the bytes in your process.
key
Keyless — no account, no card, the full read-only surface.
data
Nothing leaves the process.
TSV
case
file
connect
"./data/orders.tsv"
auth
None. SQAI reads the bytes in your process.
key
Keyless — no account, no card, the full read-only surface.
data
Nothing leaves the process.
JSON
case
file
connect
"./data/sales.json"
auth
None. SQAI reads the bytes in your process.
key
Keyless — no account, no card, the full read-only surface.
data
Nothing leaves the process.
note
A path or an object.
rows
case
in-memory
connect
[{ region: "east", revenue: 512 }, …]
auth
None. SQAI reads the bytes in your process.
key
Keyless — no account, no card, the full read-only surface.
data
Nothing leaves the process.
{ records }
case
in-memory
connect
{ records: [ … ] }
auth
None. SQAI reads the bytes in your process.
key
Keyless — no account, no card, the full read-only surface.
data
Nothing leaves the process.
SQLite
case
embedded database
connect
{ provider: "sqlite", path, table | query }
auth
None. SQAI reads the bytes in your process.
key
Keyless — no account, no card, the full read-only surface.
data
Nothing leaves the process.
note
A full database, still in-process. Name a table or a read-only query.
Excel
case
file
connect
"./data/sales.xlsx"
auth
None. SQAI reads the bytes in your process.
key
Keyless — no account, no card, the full read-only surface.
data
Nothing leaves the process.
note
Python only.
Parquet
case
file
connect
"./data/sales.parquet"
auth
None. SQAI reads the bytes in your process.
key
Keyless — no account, no card, the full read-only surface.
data
Nothing leaves the process.
note
Python only.

Through the enginecredentials encrypted · no data copied

PostgreSQL
case
relational
connect
{ type: "postgres", host, port, database, user, password, table | query }
auth
SQAI_API_KEY for the hosted engine, or SQAI_ENGINE_URL for your own.
key
A key, or your own engine URL.
data
Credentials encrypted at the engine. Rows read on demand — never copied.
MySQL
case
relational
connect
{ type: "mysql", host, port, database, user, password, table | query }
auth
SQAI_API_KEY for the hosted engine, or SQAI_ENGINE_URL for your own.
key
A key, or your own engine URL.
data
Credentials encrypted at the engine. Rows read on demand — never copied.
Oracle
case
relational
connect
{ type: "oracle", host, port, database, user, password, table | query }
auth
SQAI_API_KEY for the hosted engine, or SQAI_ENGINE_URL for your own.
key
A key, or your own engine URL.
data
Credentials encrypted at the engine. Rows read on demand — never copied.
note
Bundled Thin-mode driver — no Oracle client to install.
SQL Server
case
relational
connect
{ type: "mssql", host, port, database, user, password, table | query }
auth
SQAI_API_KEY for the hosted engine, or SQAI_ENGINE_URL for your own.
key
A key, or your own engine URL.
data
Credentials encrypted at the engine. Rows read on demand — never copied.
Snowflake
case
warehouse
connect
{ type: "snowflake", connection_string, query }
auth
SQAI_API_KEY for the hosted engine, or SQAI_ENGINE_URL for your own.
key
A key, or your own engine URL.
data
Credentials encrypted at the engine. Rows read on demand — never copied.
BigQuery
case
warehouse
connect
{ type: "bigquery", connection_string, query }
auth
SQAI_API_KEY for the hosted engine, or SQAI_ENGINE_URL for your own.
key
A key, or your own engine URL.
data
Credentials encrypted at the engine. Rows read on demand — never copied.
ClickHouse
case
warehouse
connect
{ type: "clickhouse", connection_string, query }
auth
SQAI_API_KEY for the hosted engine, or SQAI_ENGINE_URL for your own.
key
A key, or your own engine URL.
data
Credentials encrypted at the engine. Rows read on demand — never copied.
Redshift
case
warehouse
connect
{ type: "redshift", connection_string, query }
auth
SQAI_API_KEY for the hosted engine, or SQAI_ENGINE_URL for your own.
key
A key, or your own engine URL.
data
Credentials encrypted at the engine. Rows read on demand — never copied.
S3
case
object storage
connect
{ type: "s3", … }
auth
SQAI_API_KEY for the hosted engine, or SQAI_ENGINE_URL for your own.
key
A key, or your own engine URL.
data
Credentials encrypted at the engine. Rows read on demand — never copied.
GCS
case
object storage
connect
{ type: "gcs", … }
auth
SQAI_API_KEY for the hosted engine, or SQAI_ENGINE_URL for your own.
key
A key, or your own engine URL.
data
Credentials encrypted at the engine. Rows read on demand — never copied.
Azure Blob
case
object storage
connect
{ type: "azure_blob", … }
auth
SQAI_API_KEY for the hosted engine, or SQAI_ENGINE_URL for your own.
key
A key, or your own engine URL.
data
Credentials encrypted at the engine. Rows read on demand — never copied.
Redis
case
NoSQL · graph · search
connect
{ type: "redis", … }
auth
SQAI_API_KEY for the hosted engine, or SQAI_ENGINE_URL for your own.
key
A key, or your own engine URL.
data
Credentials encrypted at the engine. Rows read on demand — never copied.
Neo4j
case
NoSQL · graph · search
connect
{ type: "neo4j", … }
auth
SQAI_API_KEY for the hosted engine, or SQAI_ENGINE_URL for your own.
key
A key, or your own engine URL.
data
Credentials encrypted at the engine. Rows read on demand — never copied.
Elasticsearch
case
NoSQL · graph · search
connect
{ type: "elasticsearch", … }
auth
SQAI_API_KEY for the hosted engine, or SQAI_ENGINE_URL for your own.
key
A key, or your own engine URL.
data
Credentials encrypted at the engine. Rows read on demand — never copied.
REST
case
API
connect
{ type: "rest", … }
auth
SQAI_API_KEY for the hosted engine, or SQAI_ENGINE_URL for your own.
key
A key, or your own engine URL.
data
Credentials encrypted at the engine. Rows read on demand — never copied.
GitHub
case
code repos
connect
{ type: "github", … }
auth
SQAI_API_KEY for the hosted engine, or SQAI_ENGINE_URL for your own.
key
A key, or your own engine URL.
data
Credentials encrypted at the engine. Rows read on demand — never copied.
GitLab
case
code repos
connect
{ type: "gitlab", … }
auth
SQAI_API_KEY for the hosted engine, or SQAI_ENGINE_URL for your own.
key
A key, or your own engine URL.
data
Credentials encrypted at the engine. Rows read on demand — never copied.
Bitbucket
case
code repos
connect
{ type: "bitbucket", … }
auth
SQAI_API_KEY for the hosted engine, or SQAI_ENGINE_URL for your own.
key
A key, or your own engine URL.
data
Credentials encrypted at the engine. Rows read on demand — never copied.

Mode is inferred from the environment

SQAI_ENGINE_URLself_hosted

Your engine, your network.

SQAI_API_KEYapi

The hosted engine.

neither setlocal

In-process only.

Files and SQLite work in every mode. Live databases require api or self_hosted. The engine provisions a connection once, then stays warm — a resident daemon, no per-query cold start.

Not a sync. Not an export.
Not a third-party bridge.

direct connectivity over the database's own wire protocol

IIIThe wire

Direct. Down to the protocol.

The engine connects directly, speaking each database's own wire protocol. Queries run in place, scoped to your organization — your database is never copied.

fig. — the wire
your databaserows stay in place
its own wire protocol — spoken directly by the engine
the engineread-only queries

In place, in scope.

The engine queries your data where it lives, scoped to your organization — and never reaches beyond what you configured.

Credentials sealed.

Encrypted at rest, org-scoped, used only to serve your organization's own queries. A connector never returns its config — only name, type, status, and the last test result.

never copied

The engine never copies your database — rows are read where they live.

SELECT 1ok · connector: live

Every test opens a real connection — SELECT 1 for SQL, a HEAD for object storage, a sample fetch for REST. A connector is live only once a real connection succeeds; edit its config and it drops back to untested.

The flagship wire · Oracle

Thin mode. Nothing to install.

The engine bundles python-oracledb in Thin mode and connects directly — no Instant Client, no extra runtime process, no added Python package. The engine owns the wire end to end: the driver, the bounded connection pool, credential verification, schema browse, and an Arrow-compatible batch fetch path — never a hidden unpooled fallback connection.

  • SELECT / WITH-only roots
  • bound ROWNUM limit
  • persisted probe · reused at 0 ms

Redshift answers in PostgreSQL.

Tables are read in place over the PostgreSQL wire protocol — the cluster is never copied. Even the test success message names PostgreSQL.

One landing, every path.

Object storage and uploads share the same parsers — a Parquet object in S3 and an uploaded Parquet file land in the engine identically.

Same request → same rows, same order · every access auditable · egress is a fail-closed per-deployment allowlist

IVThe sameness

Downstream can’t tell CSV from Snowflake.

Every source returns the same typed SqaiSource — same fields, same pins, same guarantees. Swap the warehouse in for the file and nothing downstream changes.

in-process"./data/sales.csv"
through the engine{ type: "snowflake", connection_string, query }

SqaiSource

same shape · every source
name"sales"
source_ide135c6f7eec0e846c01c4ef8
fieldsregion · product · revenue · cost · units · order_date
typed_fields2 string · 3 number · 1 date
row_count12
schema_revisione4938027ddf0d2210f019770403efd45d350eac28100902ddd7c5191c9b8cfbe
statusready

One certificate, whatever the source. Downstream code never knows where the rows live.

Registered once.
Never redefined.

re-binding a name throws source_already_registered

VThe pin

Change the data. The replay says so.

connect() pins a schema revision into every plan and computation. A stored plan replayed against changed data surfaces the change — never silently different numbers.

schema_revision
Pinned at connect time into every plan and computation that touches the source.
schema_revision_mismatch
What a replay returns when the data changed underneath it.
source_already_registered
Sources are immutable — a name can never be quietly re-pointed at different data.

provenance.bindings[0]

source_name"sales"
fields["revenue"]
schema_revisione4938027…c9b8cfbe
row_count12
input_hash2ea5ede7…478e3212

Every bound field carries its lineage.

VIQuestions

LLM database access, answered.

How do I give an LLM access to my database?

Register the source in code with connect(). The model never sees a connection string — it gets three read-only tools over typed sources, and policy decides which sources and fields it may touch.

Does connecting copy my data anywhere?

No. In-process sources never leave your machine. Engine sources keep credentials encrypted; rows are read on demand and never copied.

Is SQAI a sync, an export, or a third-party bridge to my database?

None of those. Connectivity is direct over the database's own wire protocol — the engine queries your data in place, scoped to your organization, and never copies your database.

Do I need an API key to connect data?

Not for files, in-memory rows, or SQLite — those run in-process with no account at all. Live databases and warehouses need SQAI_API_KEY for the hosted engine, or SQAI_ENGINE_URL for your own.

Can the model see my credentials?

No. Credentials are supplied in your code at connect() time and encrypted at the engine. The model’s tool input carries typed intent — no connection details, no policy fields.

Is Oracle supported without installing a client?

Yes. The engine ships a bundled Thin-mode driver, so there is no Oracle client to install.

What happens when the underlying data changes?

The schema_revision pinned at connect time stops matching, and a replay surfaces schema_revision_mismatch instead of silently different numbers. Re-binding a registered name throws source_already_registered.

Connect something.

Node ≥ 20 · Python ≥ 3.10 · files & SQLite need no key