Inspiration

There is a quiet inefficiency sitting inside almost every company.

Data analysts, some of the most technically skilled people on any team, spend the majority of their time on work that never changes: the same SQL queries rewritten every week, the same dashboards rebuilt every quarter, the same numbers presented in the same recurring meetings. Meanwhile, business teams wait days for answers to questions that should take seconds.

The problem is not a lack of data. It is a lack of infrastructure to turn data into answers without a human in the loop every single time.

We started thinking about what it would look like if that entire workflow had an AI layer on top of it. Not a smarter query tool. Not a prettier dashboard builder. A genuine agent, one that understands your databases the way an analyst does, holds that understanding in memory, and can carry a full analytical task from first question to final presentation without being hand-held through every step.

That is what Luray.ai is built to be. An AI agent that does the work a data analyst does, understanding data, answering questions, building dashboards, and presenting insights in live meetings, so the humans on the team can focus on decisions, not pipelines.


What It Does

Luray.ai is an agentic AI platform that acts as an autonomous data analyst for business and data teams. Three agents work together:

1. Discovery Agent Connects to your database (PostgreSQL, MySQL, DuckDB, S3/Parquet) in read-only mode, maps the entire schema, infers relationships between tables, and classifies every table into business entities — Orders, Users, Revenue, Events. It builds AI Memory: a persistent semantic knowledge layer backed by PostgreSQL + pgvector that stores everything it learns. The agent never starts from scratch.

2. Analyst Agent Answers questions in plain English. When you ask "What was our revenue last month?", the agent searches AI Memory to understand your data model, writes the SQL, runs it against your live database, and returns the answer — as a number, a chart, or a full dashboard. It reasons step-by-step and builds persistent charts and dashboards you can revisit.

3. Communication Agent Joins your live meetings as a participant. It presents your dashboards with voice narration, walks through each chart with contextual insights, and answers verbal questions from the audience in real time using live data. Before the call ends, it has already queued the follow-up charts someone asked for.


How We Built It

Backend

  • FastAPI — async REST API with Server-Sent Events for agent streaming
  • LangGraph — multi-agent orchestration (Discovery, Analyst, Communication agents as stateful ReAct graphs)
  • DuckDB — in-memory query engine; external databases attached in READ_ONLY mode, so we never write to source data
  • sqlglot — SQL dialect transpilation (LLM-generated PostgreSQL syntax auto-converted to DuckDB dialect at execution time)
  • PostgreSQL + pgvector — persistent storage for AI Memory: semantic catalog, table embeddings, relationship graph, and conversation history
  • OpenAI / Anthropic — configurable LLM backend; the agent reasons, writes SQL, and narrates

Frontend

  • Next.js 16 + React 19 — App Router, server components, streaming
  • Tailwind CSS + shadcn/ui — component system
  • Supabase Auth — authentication with SSR session management
  • ECharts + Recharts — chart rendering
  • React Grid Layout — drag-and-drop dashboard builder
  • Framer Motion — landing page animations

Infrastructure

  • Deployed on DigitalOcean App Platform (backend) + Vercel (frontend)
  • Supabase — managed PostgreSQL with pgvector extension
  • Alembic — database migrations

Challenges We Ran Into

DuckDB dialect incompatibility The LLM writes SQL in PostgreSQL syntax (it's what it's trained on), but DuckDB doesn't support PostgreSQL-specific functions like TO_CHAR(). We solved this elegantly: sqlglot transpiles every SELECT query from postgresduckdb dialect at execution time, silently converting TO_CHAR(date, 'Mon YYYY') to strftime('%b %Y', date) and handling dozens of other dialect differences automatically.

iOS audio autoplay restrictions The Communication Agent narrates dashboards aloud. WebKit on iOS requires audio to be triggered synchronously inside a user gesture — but we were crossing async boundaries before calling .play(). The fix was architectural: one persistent HTMLAudioElement created on mount, unlocked synchronously in the "Start Presentation" button click before any await, then reused for all narration by swapping .src rather than creating new instances.

Supabase connection pooler + asyncpg prepared statements DigitalOcean's App Platform is IPv4-only; Supabase's direct connection is IPv6. The transaction pooler (port 6543) routes over IPv4 but doesn't support asyncpg's prepared statement cache. Required statement_cache_size=0 in SQLAlchemy's connect args — and discovering that Alembic creates its own engine at migration time and needed the same fix separately.

Real-time streaming across multiple workers Presentation sessions held in-process memory were lost when the load balancer routed requests to different workers. Solved by pinning to a single uvicorn worker and adding a TTL-based session cleanup task.


Accomplishments That We're Proud Of

  • End-to-end agentic loop : - from database connection to live meeting presentation, entirely autonomous, no hardcoded workflows
  • AI Memory that actually persists - the agent builds a semantic knowledge graph of your database on first run and gets meaningfully smarter with each query. It never re-discovers what it already knows.
  • Three-layer read-only enforcement - we take data safety seriously. Every source is attached with READ_ONLY at the DuckDB driver level, every SQL string is parsed by sqlglot to reject anything that isn't a SELECT, and results are row-capped. Three independent layers, any one of which blocks writes.
  • A Communication Agent that joins meetings - this feels genuinely new. The agent doesn't just answer questions in a chat box; it participates in your Zoom call, presents data with voice, and responds to the room in real time.
  • Shipped a working product - the platform is live at Luray.ai. Discovery, analysis, chart building, dashboards, and presentation mode all work end to end.

What We Learned

  • Dialect translation beats prompt engineering for SQL correctness. Telling the LLM "use DuckDB syntax" helps, but wrapping execution in sqlglot.transpile() catches what the prompt misses - and catches it every time, deterministically.
  • Audio on mobile is harder than it looks. WebKit's autoplay policy is well-documented but the subtlety — that unlocking one HTMLAudioElement instance doesn't unlock others - cost us a full debugging session.
  • Agents need persistent memory to feel intelligent. The difference between a one-shot LLM call and an agent that has read your schema, remembered what you've asked before, and built a model of your business is dramatic. That context layer is what makes Luray feel like a colleague rather than a search engine.

What's Next for Luray.ai

Near term

  • Agentic data analysis - a Jupyter-style notebook inside the platform where the agent performs exploratory data analysis autonomously (in research phase)
  • Proactive anomaly detection - agent monitors data in the background and surfaces unusual patterns before anyone asks
  • Scheduled reports - agent generates and sends PDF/email reports on a defined cadence

Longer term

  • Slack / Teams integration - query your data directly inside the tools your team already uses
  • Multi-database reasoning - agent correlates signals across all connected data sources simultaneously
  • Natural language to dbt - agent writes and documents data models from a plain English description
  • Collaborative dashboards - shared workspaces with comments, version history, and multi-user access

The long-term vision is an agent that is not a feature inside a BI tool but it is the analyst. Proactive, context-aware, always on, and present wherever decisions are being made.

Note: In the demo video, I recorded for over 8 minutes because there are numerous features to showcase. Additionally, the low audio quality at the end (The AI Agent in google meet) is due to an issue with my laptop, which prevents the audio from being clearly audible while recording.

Built With

  • anthropic
  • duckdb
  • echarts
  • fastapi
  • framer-motion
  • langgraph
  • next.js
  • openai
  • pgvector
  • postgresql
  • python
  • react
  • shadcn-ui
  • sqlglot
  • supabase
  • tailwindcss
Share this project:

Updates