Skip to main content

Grainlift ADBC gateway

The Grainlift ADBC gateway exposes a database through the standard ADBC client API. Its PyPI distribution, grainlift-adbc-gateway, contains the Rust server executable and depends on Apache's SQLite ADBC wheel. Python locates that library and launches the native server; query execution stays in Rust and the downstream driver. On Unix the launcher replaces itself with the server. On Windows it waits for the native child and lets console Ctrl-C initiate the server's graceful shutdown; service managers that forcibly stop it must terminate the process tree.

This is not the grainlift package on PyPI, which is the Python toolkit for writing your own Grainlift workers. Clients of either connect through the adbc-driver-grainlift driver.

Serve a SQLite file

Run it straight from PyPI with uv:

uvx grainlift-adbc-gateway serve sqlite ./database.sqlite

To create a database intentionally:

uvx grainlift-adbc-gateway serve sqlite ./database.sqlite --create

The service listens on 127.0.0.1:8080 and exposes target sqlite. It creates .grainlift-token in the current directory with a random 256-bit bearer token, or reuses that file on subsequent starts. Tokens are never printed. On Unix, new token files use mode 0600 and existing files must have no group/other access. On Windows, restrict the containing directory's ACL to the service account. Existing token files must be regular files, not symlinks, at most 4096 bytes, and contain at least 32 non-whitespace ASCII characters (a final newline is OK). Keep token files out of source control.

uvx grainlift-adbc-gateway serve sqlite ./database.sqlite \
  --listen 127.0.0.1:9400 --token-file ./private/service-token

Database filenames are treated as filesystem paths, not arbitrary SQLite URIs. Existing files are opened with mode=rw; missing files require --create. The parent directories for database and token files must already exist. SQLite's ordinary transaction and writer-locking constraints still apply. This exposes SQL access under the server account; it is not a SQL or filesystem sandbox. Only grant the token to callers trusted to use that access.

Clients use the native Grainlift ADBC driver with:

  • grainlift.uri: grainlift+http://127.0.0.1:8080
  • grainlift.target: sqlite
  • grainlift.auth.bearer_token: the contents of the token file, stripped of its newline

Clients cannot override the configured database URI. The shorthand only allows loopback HTTP; use the existing server configuration for remote deployments, TLS termination, mTLS, Iroh, multiple targets, JWT authentication, and quotas.

Create an Iroh identity

The Rust CLI creates identities for both servers and clients:

grainlift-adbc-gateway identity create alice.key > alice.id
grainlift-adbc-gateway identity show alice.key

create writes a new 32-byte Ed25519 private key as 64 hexadecimal characters and a newline. It prints only the derived public endpoint ID to stdout; redirection above saves that shareable ID in alice.id. show derives the same ID from an existing key, including keys created by the earlier Python helper. These commands do not read server configuration, load a database driver, or start a listener. The native grainlift-server accepts the same commands. They are also available without installing through uvx grainlift-adbc-gateway identity create alice.key.

Creation refuses to overwrite an existing file or symlink. It writes and syncs a private temporary file before publishing the completed key without replacing the destination, and removes the temporary file if publication fails. The parent directory must exist. Unix key files have mode 0600; on Windows use a directory whose ACL is restricted to the identity owner. Keep the key file private and reuse it to retain a stable endpoint identity. Only share the public ID. show accepts regular files up to 256 bytes and rejects symlinks and group/other permissions on Unix. Neither command prints private keys.

For a server, use the key path as iroh.secret_key_file. For a client, use grainlift.iroh.secret_key_file in the ADBC driver options and authorize its public ID in the server's iroh.principals map. The file is read on the client machine when opening an ADBC connection; neither its path nor contents are forwarded as downstream database options. Prefer absolute paths. The file must be regular, not a symlink, at most 256 bytes, and private on Unix (0600 or more restrictive). An inline grainlift.iroh.secret_key remains supported, but specifying both forms is an error. Existing connections retain their loaded identity; a changed file takes effect on newly opened ADBC connections.

For a shared target that should accept any verified Iroh key, use public_targets = ["sqlite"] under [iroh] instead of registering each client. The server derives a distinct principal from each unlisted key and limits it to those targets. Named mappings remain optional for additional privileges. Keep the server's existing HTTP authentication configuration. Public targets grant downstream database access to any verified Iroh peer, including writes when the target allows them. See security for the full policy.

Connect from DuckDB

DuckDB can load the native Grainlift ADBC client through the published adbc_scanner community extension. The separate Python client wheel can supply the native library path through adbc_driver_grainlift.driver_path() after installation. The connection path is DuckDB → ADBC scanner → Grainlift client driver → Grainlift server → SQLite ADBC driver. The server wheel contains the server; the client also needs the separate Grainlift ADBC shared library.

Start the service as above, or from a locally built platform wheel:

uvx --from /path/to/grainlift_adbc_gateway-0.4.0-py3-none-<platform>.whl grainlift-adbc-gateway \
  serve sqlite ./database.sqlite --create

In DuckDB, use an absolute client-library path for your platform (.dylib on macOS, .so on Linux, or .dll on Windows) and the server's token-file path:

INSTALL adbc_scanner FROM community;
LOAD adbc_scanner;
-- Temporary workaround for side-effect folding in extension 7a21dda.
PRAGMA disable_optimizer;

SET VARIABLE gl = (
    SELECT adbc_connect({
        'driver': '/absolute/path/to/libadbc_driver_grainlift.dylib',
        'entrypoint': 'AdbcDriverGrainliftInit',
        'grainlift.uri': 'grainlift+http://127.0.0.1:8080',
        'grainlift.target': 'sqlite',
        'grainlift.auth.bearer_token': trim(content, chr(10) || chr(13))
    }) FROM read_text('/absolute/path/to/.grainlift-token')
);

SELECT * FROM adbc_scan(getvariable('gl')::BIGINT, 'SELECT 42 AS answer');
SELECT * FROM adbc_tables(getvariable('gl')::BIGINT);
SELECT adbc_disconnect(getvariable('gl')::BIGINT);

Pass driver-specific options directly in the adbc_connect struct. extra_options is a parameter of CREATE SECRET (... TYPE adbc, ...), not an option container for adbc_connect. The token is read from the file instead of embedded in SQL history. The SQL string given to adbc_scan runs on the server; its result can be joined to local DuckDB tables or files. Use adbc_execute for server-side DDL and DML.

Validated on EC2 Linux AArch64 with DuckDB 1.5.5, community extension 7a21dda, and the CLI wheel from commit 4b3ac43: a 10,000-row scan, local join, table discovery, insert, persisted-write check after shutdown, and the token-file SQL example above all passed. This check used the published extension without rebuilding DuckDB or the extension.

Further lock-contention tests found a bug in published extension 7a21dda: EXPLAIN SELECT adbc_execute(...) executed a write, and a forced SQLite lock timeout took approximately three times the configured busy timeout. Disabling the DuckDB optimizer prevented the EXPLAIN write and restored the expected timeout. The recipe includes that temporary session-wide workaround pending an extension fix; it disables query optimizations in that DuckDB session.

Configuration and persistent installation

uv tool install grainlift-adbc-gateway
grainlift-adbc-gateway serve --config grainlift.toml
grainlift-adbc-gateway check --config grainlift.toml

check validates configuration and policy; it does not load drivers, connect to databases, or start listeners. GRAINLIFT_CONFIG and GRAINLIFT_SERVER_ID work as before. --config/GRAINLIFT_CONFIG cannot be combined with serve sqlite. Malformed configuration diagnostics report a byte offset when available and omit source text and key names because these can contain credentials. For configuration-based targets, use installed driver names or explicit native library paths as documented in the main README.

The standalone grainlift-server executable accepts the same commands. Its existing grainlift-server --config grainlift.toml invocation is unchanged. For SQLite shorthand outside the Python package, install the driver with dbc install sqlite --level user, or supply --driver /path/to/library. GRAINLIFT_SQLITE_DRIVER is the equivalent environment option. An explicit --driver takes precedence over the environment and packaged driver.

Build and validate a wheel

Building from source requires Rust 1.97 or newer. End users of a supported platform wheel do not need a Rust toolchain.

uv build --wheel --out-dir dist
uvx --from ./dist/grainlift_adbc_gateway-0.4.0-py3-none-<platform>.whl grainlift-adbc-gateway --help

Use the actual wheel filename. Without --from, uvx grainlift-adbc-gateway resolves the published PyPI package. CI builds platform wheels, installs each wheel in an isolated environment, and tests the CLI. Publishing requires a configured PyPI trusted publisher and the explicit release workflow; building wheels does not publish them.

Metadata

Release files for grainlift-adbc-gateway 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distributions (wheels)

Table of built distributions (wheels) for grainlift-adbc-gateway 0.4.0
File
grainlift_adbc_gateway-0.4.0-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details
grainlift_adbc_gateway-0.4.0-py3-none-manylinux_2_28_x86_64.whl Python 3 none Linux glibc 2.28+ x86-64 Details
grainlift_adbc_gateway-0.4.0-py3-none-manylinux_2_28_aarch64.whl Python 3 none Linux glibc 2.28+ ARM64 Details
grainlift_adbc_gateway-0.4.0-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details

Total release size: 49.2 MB

Release files / grainlift_adbc_gateway-0.4.0-py3-none-win_amd64.whl

Download URL grainlift_adbc_gateway-0.4.0-py3-none-win_amd64.whl
Size 11.5 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
2cc75f75342e13b1d3c823c566b459f270b35891dfb918efcbf4a4b7ed5e46c6
BLAKE2b-256 checksum
How to use checksums
43ed2baced6b96232c478300685bdd293c62a76b29559cbbf8541e653c29fa7b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.

Transparency log

Release files / grainlift_adbc_gateway-0.4.0-py3-none-manylinux_2_28_x86_64.whl

Download URL grainlift_adbc_gateway-0.4.0-py3-none-manylinux_2_28_x86_64.whl
Size 13.4 MB
Tags Linux glibc 2.28+ x86-64 Python 3
SHA-256 checksum
How to use checksums
180b1259f9952d908ed9d95245fccd4d6c4a2a72d8554ef106589b15ae049745
BLAKE2b-256 checksum
How to use checksums
56ebad00cdb66814b8b03579411d5a08f6c84a9b5a969f5f3288db15c7467998
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.

Transparency log

Release files / grainlift_adbc_gateway-0.4.0-py3-none-manylinux_2_28_aarch64.whl

Download URL grainlift_adbc_gateway-0.4.0-py3-none-manylinux_2_28_aarch64.whl
Size 13.2 MB
Tags Linux glibc 2.28+ ARM64 Python 3
SHA-256 checksum
How to use checksums
9f09ed1702cf9beb2a7646830d11973b7fc81c5436a59ed9777f1e673e1abf8c
BLAKE2b-256 checksum
How to use checksums
0d700d5336c1f5858dedb9aa3b57484411287b928bd08ff6659c5f5780c816f6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.

Transparency log

Release files / grainlift_adbc_gateway-0.4.0-py3-none-macosx_11_0_arm64.whl

Download URL grainlift_adbc_gateway-0.4.0-py3-none-macosx_11_0_arm64.whl
Size 11.1 MB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
144e1b9cce3cd22745acb3cc0a75dccce41239a162680c153f5ad3916dd79df2
BLAKE2b-256 checksum
How to use checksums
5be3b3c37890927f0d2f3d5942e5b2fe688bddebc240469d9ba6cbb6be7d1a7e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.

Transparency log

Release history Release notifications | RSS feed

0.4.3

4 release files

This release

0.4.0 This release

4 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page