StackQL 1.0 released
StackQL v1.0 is available from the releases page. It is the first major version of StackQL and the first release built on omnisdk, the replacement for the any-sdk provider backend. This post lists what changed for users since v0.12.824; the details are in the linked documentation.
New provider backend
Every provider request is now planned and executed by omnisdk, and any-sdk is no longer a dependency. Provider documents, the registry and the SQL you write are unchanged. What changed is how a statement becomes requests and rows:
- Graph planning. A statement is planned as a graph of provider exchanges joined by data and control edges. Joins, subqueries, CTEs, views and materialized views run through the same planner, and requests that fan out from a plan run concurrently within per-provider and per-host limits.
- Pushdown. Conditions that map to request parameters, and
LIMITwhere no ordering is required, are pushed into the requests rather than applied after every page has been fetched, so fewer requests are made and less data is staged. - Streaming. Rows flow from the backend as responses arrive rather than after the last page lands, which lowers peak memory use on large result sets.
Result sets are the same. The v1.0 test suite requires every mocked and live scenario to return the same rows through omnisdk as through the previous backend, and that check is mandatory in CI. Logging and debug output are not identical and will not be made so. One visible correction: boolean fields served by XML providers such as AWS are now reported as true and false rather than 0 and 1.
Session variables
SET and UNSET manage scalar variables for the current session, dereferenced with $name in any expression. Values keep their type and are resolved before the request is planned, so a variable in a WHERE clause is pushed to the provider like a literal.
SET project = 'stackql-demo';
SET zone = 'australia-southeast1-a';
SET row_count = 10;
SELECT name, status FROM google.compute.instances
WHERE project = $project AND zone = $zone
LIMIT $row_count;
Variables can also name objects. A $variable in a FROM clause resolves to a relation, and IDENTIFIER($variable) resolves to a column name in expression positions. Both are converted to identifiers in the parsed statement and never spliced into SQL text.
SET relation_name = 'aws.s3.buckets';
SET column_name = 'name';
SELECT IDENTIFIER($column_name) AS bucket
FROM $relation_name
WHERE region = 'ap-southeast-2'
ORDER BY IDENTIFIER($column_name);
See Session Variables, SET and UNSET. Session variables are separate from the Jsonnet templating variables supplied with --iqldata, which are unchanged.
Provider sessions and secrets
A session can bind a provider under an alias with its own credentials, a tenancy label, parameter defaults and request concurrency limits. Two AWS accounts can be queried in one statement:
SET "$.providers.production" = '{"provider":"aws","tenancy":"production-account",
"auth":{"type":"aws_signing_v4","access_key_id_env_var":"PRODUCTION_AWS_ACCESS_KEY_ID","secret_access_key_env_var":"PRODUCTION_AWS_SECRET_ACCESS_KEY"},
"params":{"region":"ap-southeast-2"}}';
SET "$.providers.development" = '{"provider":"aws","tenancy":"development-account",
"auth":{"type":"aws_signing_v4","access_key_id_env_var":"DEVELOPMENT_AWS_ACCESS_KEY_ID","secret_access_key_env_var":"DEVELOPMENT_AWS_SECRET_ACCESS_KEY"},
"params":{"region":"ap-southeast-2"}}';
SELECT name, 'production' AS account FROM production.s3.buckets
UNION ALL
SELECT name, 'development' AS account FROM development.s3.buckets;
Individual credential fields can be changed for the session with SET "$.auth.<provider>.<field>", and secrets can be held in session memory with SET "$.secrets.<name>" and referenced from an alias. Persistent storage in the macOS Keychain, Linux Secret Service or Windows Credential Manager is available behind the operator flag --allow-persistent-secrets; flat-file stores are refused. Secret values never enter SQL results unless the operator starts StackQL with --allow-secret-dereference.
See Provider Sessions and Secrets.
Caller access management
--access.config enables authentication and authorisation of the caller, independent of provider credentials. Four modes are supported: JWT with a pinned issuer, audience and public keys; static bearer tokens stored as SHA-256 digests; mutual TLS with a client CA and a URI or DNS SAN identity; and the local OS identity of the process. Principals, identities, groups and memberships live in four tables in the configured SQLite or PostgreSQL backend, and policy rules grant actions on resources such as host/sql/read and the operations and credentials of a provider.
SELECT whoami() AS principal, groups() AS memberships;
Access management applies to exec, shell and the MCP server over stdio and HTTPS. It is disabled by default and unprotected deployments behave as before. See Access Management.
Grammar and functions
UNSETis a new statement, andSETaccepts an explicitSESSIONscope.||is parsed as string concatenation with the standard precedence. Earlier releases tokenised||as booleanOR, which gave the wrong result when it appeared inside a comparison.CAST(expr AS TEXT | INTEGER | INT | BIGINT | BOOLEAN | BOOL)and the matchingCONVERT(expr, type)forms are accepted alongside the existing conversion types.IDENTIFIER(value)resolves a string to a column name.md5(text)returns the lowercase hexadecimal MD5 digest of its argument.whoami()andgroups()report the authenticated caller when access management is enabled.
MCP server
- Every tool carries a
titleand the four MCP behavioural hints as explicit booleans:readOnlyHint,destructiveHint,idempotentHintandopenWorldHint.openWorldHintistruefor the tools that reach provider or registry endpoints andfalsefor tools that read local state only. run_select_queryrefusesINSERT,UPDATE,REPLACE,DELETEandEXECin every server mode, includingfull_access, and namesrun_mutation_queryorrun_lifecycle_operationin the error. Previously those statements were gated by the server mode like any other payload.- With access management enabled, the HTTPS transport authenticates each request with the configured JWT, bearer or client certificate scheme in place of the shared
auth_token_env_vartoken.
Provider documents and the registry
- Signature verification of provider documents remains off by default. Setting
"verifyConfig": {"nopVerify": false}in--registryrequires an embedded ML-DSA-65 (FIPS 204) signature on every provider and service document read. Private registries supply their own keys throughverifyConfig.publicKeys. The former certificate options and.sigsidecar files are no longer used. See--registry. - Provider documents can declare endpoint selectors on server variables, resolved in a fixed order: an explicit predicate, a provider alias parameter default, the variable's environment override, the selector's environment choice, then the selector's default. Unknown selector values are errors rather than fallbacks, and
SHOW METHODSreports the resolved bindings. - Providers whose documents declare an OAuth token endpoint authenticate without an
--authentry; an explicittoken_urlin--author in a provider alias still wins. - A registry that answers with an HTTP error now reports that status instead of a parse error from the error page.
Packaging
- Release tags are
v1.0.<build>. Builds that are not from a release branch report a-rc,-alphaor-betasuffix instackql --version, and their Docker tags carry the same suffix. - The
stackql/stackqlDocker image is based on Ubuntu 26.04 LTS, and a variant with Python 3.13 preinstalled is tagged-python3.13(alias-python3). - The ChatGPT, Codex and Claude Code plugins for the MCP server are built from one vendored launcher that needs only Node.js built-ins. See Installing StackQL.
Preview
Behind --preview '{"unstable": true}', the stackql_preview.iac.run and stackql_preview.iac.destroy relations apply and tear down a declared set of resources through the converging run in omnisdk: the collection is locked for the run, intent is journalled before each effect, and a failed run is undone. State is kept under the application root. This surface is a preview; its syntax and output can change between releases.
Upgrading
No changes are required to existing queries, provider documents or configuration files. Review the following if your scripts depend on them:
- Boolean columns from XML providers return
trueandfalseinstead of0and1. - Expressions that relied on
||being parsed asORmust useOR. - MCP clients that sent writes through
run_select_querymust userun_mutation_queryorrun_lifecycle_operation. stackql execexits with status1when aSETorUNSETconfiguration statement fails, when access management is enabled and a statement is refused, or when a preview IaC run reports a failed resource.
Binaries, installers, MCP bundles and container images are listed on the installation page.