Supported Databases
The currentnao CLI supports these database types in nao_config.yaml:
- Athena
- BigQuery
- ClickHouse
- Databricks
- DuckDB
- Fabric
- MSSQL
- MySQL
- Postgres
- Redshift
- Snowflake
- StarRocks
- Trino
Common Parameters
Every database entry supports these shared fields:name: Friendly connection nametype: One ofathena,bigquery,clickhouse,databricks,duckdb,fabric,mssql,mysql,postgres,redshift,snowflake,starrocks,trinoinclude: Optional glob patterns forschema.tablevalues to includeexclude: Optional glob patterns forschema.tablevalues to excludeexclude_columns: Optional glob patterns forschema.table.columnvalues to hide (see below)templates: Optional list of rendered context files
Excluding columns
include and exclude filter at the table level. To drop individual columns from everything the agent sees (column lists, previews, and profiling), use exclude_columns. Patterns are glob-matched against the fully-qualified schema.table.column name:
The
templates field used to be called accessors. The old key still works (nao will read it and migrate automatically), but new configs should use templates.Templates
These are the built-in templates nao can render per table:columns(default; schema plus the table description, row count, and partitioning metadata)preview(default; sample rows)query_history(default; AI-friendly per-table usage context built from your warehouseβs query history)profiling(optional; column-level statistics)ai_summary(optional; AI-generated table summary)
templates, nao renders columns, query_history, and preview by default.
The table description, row count, partitioning, and clustering metadata all live in columns.md. profiling.md repeats the clustering columns on a short Clustering: line alongside its statistics.
nao init scaffolds a smaller set than the config-file default: columns and preview, plus ai_summary when you configure an LLM. It writes profiling and query_history as commented-out options you can uncomment later.Migrating from
how_to_use / description. The how_to_use template was renamed to query_history, and the standalone description template was removed (its content moved into columns.md). Both old names still load: nao migrates them automatically and prints a FutureWarning asking you to rename how_to_use to query_history (and drop description) in nao_config.yaml. Existing how_to_use.md and description.md files already written to disk are not removed automatically yet (tracked in getnao/nao#1193), so delete them by hand for now.query_history
query_history produces a single markdown file per table built from your warehouseβs query history:
- How often the table is queried
- The tables it is most often joined with
- The most frequently run queries against it
columns.md.
To enable query-history-based context, set query_history_days on the database (defaults to 0, meaning no history is fetched):
query_history reports that no history was found; the table metadata is always available in columns.md.
Customizing query history
Two optional fields let you control which queries feed into thequery_history analysis:
query_history_sql overrides the built-in history query for a database. The SQL must return a query_text column. Use the {days} placeholder to inject the configured query_history_days value:
query_history_exclude_patterns filters out noise after fetching. Each entry is a case-insensitive regex. Any query whose text matches at least one pattern is dropped before analysis:
profiling
Use the optional profiling config block to control profiling refresh behavior:
refresh_policy: When to recompute profiling. One ofalways(default, every sync),interval(everyinterval_daysdays), oronce(only when the file is missing).interval_days: Refresh interval in days whenrefresh_policy: interval(default7, minimum1).
array, struct, map, json, row, tuple, variant, object, super). For array columns, nao unpacks the values before computing distinct counts and top values; other complex types are stringified before profiling.
ai_summary
ai_summary is opt-in. To use it, add ai_summary to templates and configure llm.annotation_model in nao_config.yaml.
When enabled, nao renders databases/ai_summary.md.j2 and calls prompt("...") inside that template to generate LLM-based summaries during nao sync.
The summary bases its data-quality and distribution notes on the full-table profiling statistics (empty counts, unique counts, min/max, most common values), which nao computes once per table and shares with the summary. The preview rows are treated as a small, non-representative sample, so the summary never infers data quality from them; when no profiling statistics are available it stays silent about data quality.
ai_summary takes the same refresh config as profiling:
refresh_policy: When to regenerate the summary. Defaults toalways, so existing setups keep regenerating it on every sync.interval_days: Refresh interval in days whenrefresh_policy: interval(default7, minimum1).
Database Parameters
Athena
profile_nameaws_access_key_idaws_secret_access_keyaws_session_token
BigQuery
credentials_pathcredentials_jsonsso: truefor ADC / browser auth
partition_filters: map oftable_name: SQL filterused for preview queries on tables that enforcerequire_partition_filter = TRUE
Limit query size
Usemax_query_size (in GB) to cap how much data a single query can scan. When set, nao runs a BigQuery dry run before every SQL execution and rejects the query if the estimated bytes processed exceed the limit.
- The check applies to every query the agent runs - chat, stories, evaluations, anything going through
nao chatornao test. - The limit is enforced before BigQuery scans the data, so blocked queries cost nothing.
- Errors include the estimated bytes and the configured limit so the agent can suggest a tighter filter and retry.
- Leave the field unset (or set it to
0) to disable the check.
nao init, the CLI prompts for a maximum query size as part of the interactive setup. The same field is available in the IDE under Settings -> Warehouse Connections for the cloud and IDE flows.
Partition vs clustering columns
For BigQuery tables,nao sync exposes partition columns and clustering columns as separate sections in each tableβs context. The agent uses partition columns to enforce WHERE filters that prune scanned bytes, and clustering columns to recommend the right join keys and predicate ordering for performance. Both are detected automatically - no config required.
Both partition and clustering columns are written to columns.md; profiling.md also repeats the clustering columns on a short Clustering: line. Columns hidden via exclude_columns are filtered out of the clustering list too.
Native column types
For BigQuery, generated context reports the native BigQuery type rather than the normalized internal type. This matters becauseDATETIME and TIMESTAMP are distinct in BigQuery, and documenting both as a generic timestamp led the agent to write invalid SQL (for example TIMESTAMP_SUB on a DATETIME column). columns.md, ai_summary.md, and profiling.md now show INT64, DATETIME, TIMESTAMP, and so on. If the INFORMATION_SCHEMA lookup fails, nao falls back to the normalized types.
Separately, 64-bit integer columns are no longer reported as int32 in profiling on any warehouse. BigQuery INT64, Snowflake INTEGER / NUMBER(38,0), and BIGINT columns elsewhere are now profiled with their true width.
ClickHouse
columns.md, so no separate template is needed for it.
Connection protocol
nao connects to ClickHouse over the HTTP interface by default. For deployments that only expose the native TCP protocol (ports 9000 / 9440), set protocol: native:
protocol: http (the default) keeps the existing behavior, no change needed for current configs. When prompting with nao init, the default port flips automatically based on the protocol you pick (8123/8443 for HTTP, 9000/9440 for native).
secure: true means HTTPS on protocol: http and TLS over TCP on protocol: native. On the native protocol you can add verify: false to skip TLS certificate verification (for example against a self-signed internal certificate):
connect_timeout and send_receive_timeout, both in seconds.
Databricks
temp_schema to a schema you have write access to:
temp_schema is set it becomes the connection schema in place of schema_name; schema_name still drives which schema is synced. nao init prompts for it during interactive setup. Leave it unset if your default schema is already writable.
DuckDB
Fabric
sql_password(SQL username/password)azure_cli(az logintoken)azure_interactive(browser login)azure_service_principal(client ID and secret)
MSSQL
MySQL
Postgres
Redshift
Snowflake
private_key_pathpassphraseauthenticatortoken
Snowflake semantic views
When the agent runsnao sync against Snowflake, it also imports any semantic views declared in your account. Each view (metrics, dimensions, relationships pulled from INFORMATION_SCHEMA.SEMANTIC_VIEWS) is written to:
nao sync skips the step silently. No new fields in nao_config.yaml.
StarRocks (type: starrocks)
catalogs list:
SHOW statements.
Trino
http_scheme: https for TLS-only coordinators (Starburst, Stackable, OPA-authorized OSS Trino). Password authentication requires it:
verify controls certificate validation and only applies when http_scheme: https:
true(default): verify against the system CA bundlefalse: disable verification- a path: verify against a custom CA bundle, for an internal CA
jwt_token_file at a file that an external refresher rewrites. nao re-reads the file on every connection, so rotation needs no config change:
jwt_token_file, then jwt_token, then password. A JWT always forces http_scheme: https, even if the config says http, so the bearer token is never sent in cleartext. If the token file is missing or empty, nao falls back to jwt_token and then to password auth.
When syncing Trino tables, nao automatically imports table-level comments from system.metadata.table_comments and column-level comments from DESCRIBE. These comments appear in the generated context files alongside schema metadata, giving the agent richer descriptions without any extra configuration.
SQL dialect handling
When the agent generates SQL, nao auto-detects the warehouse dialect from the target databaseβstype and injects extra rules into the system prompt so the query uses the right syntax:
- T-SQL (MSSQL, Fabric): use
TOP Ninstead ofLIMIT. - BigQuery: quote identifiers with backticks and use
SAFE_DIVIDE(a, b)instead ofa / bto avoid divide-by-zero errors. - MySQL: quote identifiers with backticks and use
IFNULLinstead ofCOALESCEfor null handling.
Synchronization
Once configured, sync your database schemas:- Connect to each database
- Extract schema information
- Render the configured templates
- Save the output in
databases/
Context Files
After syncing, youβll see a structure like:Generated vs manual files
Every filenao sync writes carries a YAML frontmatter header saying who owns it, so it is clear at a glance what will be overwritten on the next sync.
Generated files (columns.md, preview.md, query_history.md, profiling.md, ai_summary.md, and Snowflake definition.md) start with:
nao sync creates one annotations.md per table folder for your own notes:
annotations.md is created empty below the header, and never overwritten: subsequent syncs leave an existing file untouched. Use it for table-specific rules the agent should honor that your warehouse metadata does not carry, for example βthis table double-counts refunds, join to fct_refunds to net them outβ. For rules that apply across tables, use RULES.md instead.
Example generated files:
columns.md
columns.md. There is no separate description.md file anymore.
preview.md
profiling.md
**Clustering:** line only appears when the warehouse reports clustering, sort key, or liquid clustering columns for the table.
Table Selection
Control which tables are synced withinclude and exclude.
Use glob patterns on schema.table:
analytics.ordersanalytics.**.orders*_stagingtest_**
include first and then removes matches from exclude.
Best Practices
- Start with your core schemas only
- Keep
templatessmall if token usage matters - Use
includeandexcludeto avoid temp, backup, and test tables
Context Engineering Principles
Learn how to find the optimal balance between comprehensiveness and efficiency