Build dashboards your whole team can trust. Define metrics once, explore without waiting on the data team, and ship changes that never break production — in the UI, with AI, or in version-controlled c
DataJavaScript · PythonGitHub @visivo-ioOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
✨ Build dashboards with end-to-end version control. 🔋 CLI w/ batteries included, no infra required. Develop on your laptop for instant results, deploy changes safely (with automated checks), and keep every report trustworthy for stakeholders, analysts and agents 🤖
Taken from the repository README
Loading the full README.
Read the full README ↗pip install visivo # Python 3.12+
visivo init --example ev-sales # copies a sample project, starts the dev server, opens the browser
init --example writes a project.visivo.yml, a small DuckDB file and the CSV it came from, then runs visivo serve on http://localhost:8000. The other bundled examples are github-releases and college-football.
Prefer a single binary with no Python? curl -fsSL https://visivo.sh | bash installs one to ~/.visivo/bin (macOS 15+, Linux x86_64, Windows through WSL). To start from your own data, run visivo init and the in-browser wizard walks you through adding a source.
Edit the YAML and save. The dev server recompiles and re-runs what changed, and layout and style edits redraw in the open tab without a reload. No build step.
Every Visivo project is the same chain of objects: a source you query, models that name a SQL query, a semantic layer of metrics, dimensions and relations on top of those models, insights that pick fields and aggregates to plot, charts that give insights a Plotly layout, and dashboards that lay charts, tables, markdown and inputs out in rows.
sources:
- name: taxi
type: duckdb
database: taxi.duckdb
models:
- name: trips
source: ${ref(taxi)}
sql: SELECT * FROM yellow_trips
metrics:
- name: revenue
expression: SUM(total_amount)
- name: tip_rate
expression: SUM(tip_amount) / SUM(fare_amount)
dimensions:
- name: pickup_week
expression: date_trunc('week', tpep_pickup_datetime)
- name: payment_method
expression: CASE payment_type WHEN 1 THEN 'Credit card' WHEN 2 THEN 'Cash' ELSE 'Other' END
inputs:
- name: payment
type: single-select
options: ["Credit card", "Cash"]
insights:
- name: revenue_by_week
props:
type: scatter
mode: lines
x: ?{ ${ref(trips).pickup_week} }
y: ?{ ${ref(trips).revenue} }
interactions:
- filter: ?{ ${ref(trips).payment_method} = '${ref(payment).value}' }
charts:
- name: revenue_by_week_chart
insights:
- ${ref(revenue_by_week)}
layout:
title:
text: Weekly revenue
dashboards:
- name: Revenue
rows:
- height: compact
items:
- input: ${ref(payment)}
- height: medium
items:
- chart: ${ref(revenue_by_week_chart)}
?{ } wraps a SQL expression. ${ref(object).field} points at a model column, a metric, a dimension or an input value, and Visivo resolves the joins and the GROUP BY for you. Define revenue once and every insight that references it computes it the same way.
It is code, so it gets the software workflow. Projects are YAML in git. A dashboard change is a branch, a diff and a pull request. In CI, visivo run executes the queries and visivo deploy -s <stage> publishes a preview stage named after the branch to Visivo Cloud, so a reviewer opens the rendered dashboard next to the diff. visivo archive -s <stage> cleans it up when the PR closes. The CI/CD guide has a complete GitHub Actions workflow.
A semantic layer that people and agents share. Metrics, dimensions and relations live in the project, not in each chart. Model columns are dimensions by default; relations declare how models join so an insight can pull fields from two models and get the right SQL. The same definitions are what the built-in agent and external MCP clients read before they write anything.
Interactive without round trips. Inputs (dropdowns, radios, tabs, sliders, range sliders, date ranges, chips, checkboxes) feed filter, split and sort interactions. Those run in the browser on the insight's pre-computed data through DuckDB-WASM, so switching a filter re-aggregates instantly and never touches your warehouse.
Local first. visivo serve runs the project, watches your files and rebuilds on every save. The same server hosts a workspace where you can explore a source, draft insights against live data, lay out a dashboard on a canvas, edit the theme, and commit the result back to your YAML.
Layout is drag and drop: pull a chart from the Library onto a row, grab a selected card by its frame to reorder it, then save the result to the YAML.
Push, not pull. visivo run executes the queries wherever you run it, on your laptop or in CI, and writes the results next to the project. visivo deploy ships those results, so the hosted viewer never needs a connection to your warehouse.
Visivo ships an agent and an MCP server. Both use the same tools and the same packaged skills, and neither can write your YAML files or commit: every write lands as a draft that you review in the workspace, then commit or discard.
Your agent, over MCP. visivo serve exposes http://localhost:8000/api/mcp/ (Streamable HTTP, no auth on localhost). Point Claude Code, Cursor, Gemini CLI or any MCP client at it:
claude mcp add --transport http visivo http://localhost:8000/api/mcp/
The server offers list_*, get_*, validate_* and write_* for every project object type (sources, models, metrics, dimensions, relations, insights, charts, tables, markdown, inputs, dashboards), read-only data tools (describe_source, query_source, profile_model, profile_columns, preview_insight), charting advisors (recommend_charts, recommend_inputs, check_input_wiring, recommend_layout, score_candidates) and read_skill for the packaged skills such as choose-a-chart, design-a-dashboard and make-it-interactive. The skills encode measured chart rules for every Plotly trace type, so an agent gets the chart family, the input wiring and the layout right instead of guessing.
The built-in agent. The Agent tab in visivo serve runs the same loop with your own Anthropic, OpenAI or Google key, or with inference from your Visivo Cloud account. visivo init also writes an AGENTS.md where you keep naming rules and business definitions for either path. Read Build with AI for the four ways to run it and the draft boundary.
dbt: block turns your dbt models and targets into Visivo models and sources (visivo dbt refreshes them).theme: block for colorway, fonts and surfaces, and a plotly_layout escape hatch.options: ?{ SELECT DISTINCT region FROM ${ref(sales)} } fills a dropdown from your data at build time.visivo dist packages the viewer and the last run's data into a folder you can host on S3, GitHub Pages or any static host.visivo deploy pushes the project and its data to app.visivo.io under a named stage, with sharing, teams and roles.Rows stack on phones, so the same dashboard reads on a 390 px screen.
| GUI BI tools (Tableau, Looker, Power BI, Metabase, ...) | Visivo | |
|---|---|---|
| Definition | Click-built in a GUI; hard or impossible to version | YAML in git |
| Review | No diff, no pull request | Branch, diff, PR, preview stage |
| Environments | Usually one shared instance | Named stages for dev, CI and production |
| Data access | You hand the vendor credentials to pull your data | You run the queries and push the results |
| Agents | Vendor chat features over vendor-held metadata | A local MCP server and a built-in agent over the same project files, drafts you review |
| Where it lives | Outside your transformation stack | Next to your dbt, Django or Rails project |
Visivo is not a warehouse, a transformation tool or a notebook. It reads the tables you already have and turns them into reviewable dashboards.
visivo/, React viewer in viewer/, tests in tests/Visivo collects anonymous usage telemetry (command names, no queries, no file contents, no personal data). Run visivo telemetry off to opt out on a machine, or set VISIVO_TELEMETRY_DISABLED=true. Details are in the telemetry docs.
Visivo is released under the GNU General Public License v3.0.