nao: a self-hosted analytics agent built around a context folder
👾 nao is an open source analytics agent. (1) Create context with nao-core cli, (2) deploy nao chat interface for everyone
At a glance
- What is it?
- nao splits the work of a chat-with-your-data agent into two halves: a Python CLI that assembles context from your warehouse and repos, and a TypeScript chat UI you self-host. The design is opinionated about where context lives, and the README leaves the LLM and warehouse wiring mostly to the docs site.
- Who is it for?
- Adopt nao if your data team already treats warehouse metadata and SQL conventions as artifacts worth versioning, and you want the agent's context to live in a folder you can diff and test rather than inside a vendor's settings page. Skip it if you need a managed product with a support contract, or if nobody on the team will maintain the context files after the initial sync.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The problem nao targets: context that nobody versions
Most text-to-SQL tools put the burden of accuracy on the model and the schema dump. nao takes a different position. The README describes it as a framework to build and deploy an analytics agent, and the first half of that sentence is the interesting one: you build the context with the nao-core CLI, covering data, metadata, modeling, rules and whatever else you want to add. The claim in the feature list is that there is no limit to what goes in, including tools and MCP servers. That is a context engineering problem stated as a product feature. The audience is data teams who already maintain dbt models, metric definitions or naming conventions, and who have watched a chat interface give a plausible answer built on the wrong join. The secondary audience is business users, who get the chat UI and never see the folder. nao's bet is that the gap between those two groups is closed by files on disk rather than by prompt tuning inside a black box.
How the context folder and the sync step fit together
The mechanism visible in the README is a project directory. nao init creates a folder named after your project, an architecture for context files, a nao_config.yaml, and a RULES.md. The RULES.md file is where you would write the conventions the agent should follow, and it sits in the same tree as the synced material. nao sync is the step that populates that folder from your context sources, which the command list describes as databases and repos. So the data flow is: sources are read by the CLI, written into the project folder as files, and the chat interface reads the folder at question time. The Docker instructions reinforce this. When you mount a local project, you pass -v /path/to/your/nao-project:/app/project together with -e NAO_DEFAULT_PROJECT_PATH=/app/project, which means the container is pointed at the same folder the CLI produced. That is a clean separation, and it also means the quality of the agent is bounded by what nao sync actually pulled in. The README does not describe how much of a large warehouse gets synced, or whether there is a size limit, so that is something to check against the docs before pointing it at a production schema.
Getting it running: the CLI path and the Docker path
The README gives a five-step quickstart. Install the Python package with pip install nao-core, then run nao init, which interactively asks for a project name and optionally a database connection, a repo to add to context, an LLM key, and a Slack connection. Every optional question can be skipped and configured later in nao_config.yaml. After that, cd into the project folder and run nao debug to verify the setup, then nao sync to populate context, then nao chat, which serves the UI at http://localhost:5005. The Docker route skips the Python install. docker pull getnao/nao:latest, then docker run -d --name nao -p 5005:5005 -e BETTER_AUTH_URL=http://localhost:5005 getnao/nao:latest runs the bundled example project. Swapping in your own project means adding the volume mount and NAO_DEFAULT_PROJECT_PATH. Note the environment variable name: BETTER_AUTH_URL, which the README says is used for authentication, trusted origins and Slack redirects. If you deploy behind a proxy or on a non-localhost hostname, that value has to match the public URL or the auth flow will not line up. For development from source, the README lists nvm, bun and uv as prerequisites, then npm run npm:pin, npm install, npm run db:migrate -w apps/backend, and a root .env containing BETTER_AUTH_SECRET, BETTER_AUTH_URL, OPENAI_API_KEY and NAO_DEFAULT_PROJECT_PATH. The dev server runs on port 3000, not 5005.
The evaluation loop is the part worth paying attention to
nao ships a testing command that most tools in this category do not. You create a tests/ folder containing questions and expected SQL in YAML, then run nao test to measure the agent against those examples, and nao test server to view results in a panel. The README frames this as unit testing the agent before deploying it to users, and pairs it with versioning the context and tracking performance over time. This is the strongest argument in the repository, because it turns an argument about whether the agent is good into a number you can recompute after every context change. It also sets an expectation: if you write tests with expected SQL, you are asserting that there is one correct query, which is not always true for analytical questions where several queries return the same answer. Expect to spend time curating the test set, and expect some tests to fail for reasons that are about your expectations rather than the agent. The README does not state how the comparison between generated and expected SQL is performed, so whether it is exact match or something looser is worth confirming before you build a workflow around it.
What the repository does not tell you
The licence is listed as NOASSERTION, which means the repository metadata does not map to a recognised SPDX identifier. For a self-hosted tool that you may run inside a company network and potentially redistribute internally, that is a gap you have to close by reading the actual LICENSE file rather than trusting the badge. The README also does not describe what happens when a synced context goes stale: if a column is renamed in the warehouse, nao sync presumably refreshes the files, but nothing in the supplied material says whether the agent detects drift or silently answers with the old definition. The feature list claims the tool is data stack agnostic and works with any warehouse, stack, LLM or type of context, yet the only concrete integrations named anywhere in the README are the topics list (BigQuery, Databricks, PostgreSQL, Snowflake) and a single OPENAI_API_KEY in the development environment example. The breadth claim is plausible for an agent that reads files, but it is a claim, not a demonstrated list. Treat the docs site, not the README, as the place where connector support is settled.
Where nao is the wrong choice
If your organisation wants a hosted product with an SLA, nao is the wrong fit by construction. You supply the LLM key, you run the container, you mount the volume, and you keep the context folder current. The README is explicit that self-hosting and your own LLM keys are the security model, which is a benefit only if you have someone to operate it. A second failure mode is organisational rather than technical: the context folder is only as good as the discipline behind it. An agent whose RULES.md was written during a pilot and never touched again will drift away from how the team actually models data, and the feedback mechanism (business users flagging right or wrong answers) only helps if the data team reads those flags. A third case: teams that want an agent to explore an unfamiliar schema with no prior modelling work will get less from nao than from a tool that leans harder on schema introspection, because nao's whole premise is that you bring the context rather than expecting the agent to infer it.
Compared with a general-purpose agent framework
The obvious alternative is assembling the same thing from a general agent framework plus a SQL tool and a chat front end. That path gives you control over every prompt and every retry, and it does not ask you to adopt a project layout. The difference in approach is where the abstraction sits. nao fixes the layout: a project folder, nao_config.yaml, RULES.md, a tests/ directory with YAML questions and expected SQL, and a CLI whose verbs are init, sync, test, debug and chat. A general framework gives you primitives and no opinions, so you write the sync step, the test harness and the UI yourself. nao's evaluation command is the concrete thing you would otherwise have to build, and it is the reason to prefer nao over hand-rolling unless your context sources are unusual enough that nao sync cannot reach them. The reverse also holds: if your warehouse access is locked down in a way that the CLI's connection flow does not accommodate, the fixed layout becomes a constraint rather than a shortcut.
Maintenance, releases and what to verify first
The release history shows a steady cadence through v0.3.x in September 2026, with a separate helm chart at helm-v0.1.1. Version numbers in the 0.3 range mean the interface can still move, and a config file created by nao init today may need editing after an upgrade. Budget for that: keep nao_config.yaml and RULES.md under version control so an upgrade that changes expected keys shows up as a diff rather than a broken agent. The Python CLI and the TypeScript application version separately in practice, since one is installed via pip and the other via Docker or npm, so pin both. Before rolling nao out to business users, verify three things in order: that nao debug passes against your real warehouse credentials, that nao test produces results you consider meaningful on a small curated question set, and that BETTER_AUTH_URL is set to the exact public URL the users will hit. Those three checks cover the setup, the accuracy and the login path, which are the places where a self-hosted deployment fails quietly.
Editorial conclusion
Adopt nao if your data team already treats warehouse metadata and SQL conventions as artifacts worth versioning, and you want the agent's context to live in a folder you can diff and test rather than inside a vendor's settings page. Skip it if you need a managed product with a support contract, or if nobody on the team will maintain the context files after the initial sync. Before committing, run nao debug and nao test against a small set of questions with expected SQL to see whether the context you synced is actually enough for the agent to produce correct queries.
Community notes