Skip to main content

dashboardmd

Code-first analytics dashboard platform. Connectors for everything. Markdown output.

Universal data model — same concepts as Metabase, Looker, PowerBI, Cube — but in Python, for agents, with composable connectors that work together.

The Core Idea

Every analytics platform uses the same foundational concepts:

  1. Entities (tables/views with semantic meaning)
  2. Dimensions (attributes you group and filter by)
  3. Measures (aggregations you compute)
  4. Relationships (how entities join together)
  5. Queries (select measures + dimensions → get results)
  6. Dashboards (tiles bound to queries + global filters)

dashboardmd mirrors these concepts in Python. Connectors are the universal integration layer — whether your data comes from CSV files, REST APIs, BI platforms, or community packages, everything plugs into the same system.

     Connectors                           Built-in
  ┌──────────────────────────┐     ┌───────────────────────┐
  │ Data Connectors          │     │ File Sources           │
  │  • Custom (your code)    │     │  • CSV / Parquet / JSON│
  │  • Community (pip)       │     │  • DuckDB / SQLite     │
  │  • API / Callable        │     │  • PostgreSQL / MySQL  │
  │                          │     │  • pandas DataFrames   │
  │ BI Platform Connectors   │     │                       │
  │  • MetabaseConnector     │     │ Semantic Layer         │
  │  • LookMLConnector       │     │  • Entity / Dimension  │
  │  • CubeConnector         │     │  • Measure / Query     │
  │  • PowerBIConnector      │     │  • Relationship        │
  └────────────┬─────────────┘     └───────────┬───────────┘
               │                               │
               └───────────────┬───────────────┘
                               ▼
                    ┌──────────────────┐
                    │   dashboardmd    │
                    │    Analyst       │  ← DuckDB engine
                    │  analyst.use()   │  ← composable connectors
                    └────────┬─────────┘
                             │
                             ▼
                ┌──────────────────────────┐
                │      Markdown Report     │
                │        (.md files)       │
                └──────────────────────────┘

Installation

pip install dashboardmd

With optional dependencies:

pip install "dashboardmd[pandas]"      # DataFrame support
pip install "dashboardmd[plotting]"    # Chart images via matplotlib
pip install "dashboardmd[all]"         # Everything

Quick Start

Direct SQL with Analyst (maximum agent power)

The Analyst is the core of dashboardmd — a DuckDB-powered query engine that gives AI agents full analytical SQL capabilities over any data source.

from dashboardmd import Analyst

# Create an analyst and register data sources
analyst = Analyst()
analyst.add("orders", "data/orders.csv")
analyst.add("customers", "data/customers.csv")

# Full DuckDB SQL — aggregations, window functions, CTEs, JOINs, pivots, regex...
result = analyst.sql("""
    SELECT
        c.segment,
        COUNT(*) AS order_count,
        SUM(o.amount) AS revenue,
        AVG(o.amount) AS avg_order_value
    FROM orders o
    JOIN customers c ON o.customer_id = c.id
    WHERE o.status = 'completed'
    GROUP BY 1
    ORDER BY revenue DESC
""")

# Multiple output formats
result.show()                  # Print to stdout
result.to_markdown_table()     # Render as Markdown table
result.df()                    # Return as pandas DataFrame
result.fetchall()              # Raw tuples
result.scalar()                # Single value

# Schema exploration (great for agents)
analyst.tables()               # List all tables
analyst.schema("orders")       # Column names and types
analyst.sample("orders", 5)    # Preview rows
analyst.count("orders")        # Row count

# Write results to Markdown
analyst.to_md("output/analysis.md", title="Revenue Analysis", queries=[
    ("By Segment", "SELECT segment, SUM(amount) FROM orders GROUP BY 1"),
    ("Top 10", "SELECT * FROM orders ORDER BY amount DESC LIMIT 10"),
])

Semantic Queries (BI-style)

Build on top of Analyst with entities, dimensions, and measures — same concepts as Looker, PowerBI, Cube, and Metabase.

from dashboardmd import Analyst, Entity, Dimension, Measure, Relationship

# Define entities (like Looker views, PowerBI tables, Cube cubes)
orders = Entity("orders", source="data/orders.csv", dimensions=[
    Dimension("id", type="number", primary_key=True),
    Dimension("date", type="time"),
    Dimension("customer_id", type="number"),
    Dimension("status", type="string"),
], measures=[
    Measure("revenue", type="sum", sql="amount"),
    Measure("count", type="count"),
])

# Register entities and query semantically
analyst = Analyst()
analyst.add_entity(orders)
result = analyst.query(measures=["orders.revenue"], dimensions=["orders.status"])
print(result.to_markdown_table())

Dashboards (structured reports)

from dashboardmd import Dashboard, Entity, Dimension, Measure, Relationship

orders = Entity("orders", source="data/orders.csv", dimensions=[
    Dimension("id", type="number", primary_key=True),
    Dimension("date", type="time"),
    Dimension("customer_id", type="number"),
    Dimension("status", type="string"),
], measures=[
    Measure("revenue", type="sum", sql="amount", format="$,.0f"),
    Measure("count", type="count"),
])

customers = Entity("customers", source="data/customers.csv", dimensions=[
    Dimension("id", type="number", primary_key=True),
    Dimension("name", type="string"),
    Dimension("segment", type="string"),
])

rels = [
    Relationship("orders", "customers", on=("customer_id", "id"), type="many_to_one"),
]

# Build the dashboard
dash = Dashboard(
    title="Weekly Business Review",
    entities=[orders, customers],
    relationships=rels,
    output="output/weekly.md",
)

dash.filter("date_range", dimension="orders.date", default="last_30_days")

dash.section("Key Metrics")
dash.tile("orders.revenue", compare="previous_period")
dash.tile("orders.count", compare="previous_period")

dash.section("Revenue by Segment")
dash.tile("orders.revenue", by="customers.segment", type="bar_chart")

# Raw SQL tiles — full DuckDB power inside dashboards
dash.section("Custom Analysis")
dash.tile_sql("Top Customers", """
    SELECT c.name, SUM(o.amount) AS total
    FROM orders o JOIN customers c ON o.customer_id = c.id
    GROUP BY 1 ORDER BY 2 DESC LIMIT 5
""")

dash.save()  # → output/weekly.md

Connectors

Connectors are the universal integration layer. A connector bundles everything needed to analyze a data domain: data sources, cleaning, entity definitions (dimensions/measures), relationships, and pre-built dashboard widgets.

Composable by design

Multiple connectors install into one Analyst and work together:

from dashboardmd import Analyst, Relationship
from dashboardmd.connectors import MetabaseConnector

analyst = Analyst()

# BI platform connector — import your existing Metabase model
analyst.use(MetabaseConnector(metabase_metadata))

# Community connector — pip install dashboardmd-github
analyst.use(GitHubConnector(token="...", repo="org/repo"))

# Custom connector — your own data
analyst.use(MyInternalConnector(api_key="..."))

# Cross-connector joins — link data across boundaries
analyst.add_relationship(Relationship(
    "orders", "pull_requests", on=("id", "order_id"), type="one_to_many"
))

# Query across everything as one system
analyst.query(
    measures=["orders.revenue"],
    dimensions=["pull_requests.author"],
)

BI Platform Connectors (built-in)

Import data models from any BI platform. They implement the same Connector interface, so they compose with data connectors:

from dashboardmd import Analyst
from dashboardmd.connectors import MetabaseConnector, LookMLConnector, CubeConnector, PowerBIConnector

# Import from Metabase
analyst = Analyst()
analyst.use(MetabaseConnector(metabase_metadata_dict))

# Import from LookML / Looker
analyst.use(LookMLConnector(lookml_model_dict))

# Import from Cube.js
analyst.use(CubeConnector(cube_schema_dict))

# Import from PowerBI
analyst.use(PowerBIConnector(powerbi_model_dict))

Custom Connectors

Build your own connector for any data domain:

from dashboardmd import Connector, DashboardWidget, Entity, Dimension, Measure
from dashboardmd.sources.base import SourceHandler

class MyAPISource(SourceHandler):
    def __init__(self, url, token):
        self.url = url
        self.token = token

    def register(self, conn, table_name):
        rows = self._fetch()           # your API logic
        rows = self._clean(rows)       # your cleaning logic
        self._register_rows(conn, table_name, rows)  # built-in helper

    def describe(self):
        return {"columns": []}

class MyConnector(Connector):
    def __init__(self, api_key):
        self.api_key = api_key

    def name(self):
        return "my_service"

    def sources(self):
        return {"events": MyAPISource("https://api.example.com/events", self.api_key)}

    def entities(self):
        return [Entity("events", dimensions=[
            Dimension("id", type="number", primary_key=True),
            Dimension("type", type="string"),
            Dimension("timestamp", type="time"),
        ], measures=[
            Measure("count", type="count"),
        ])]

    def widgets(self):
        return [DashboardWidget(
            name="Overview",
            title="Event Analytics",
            requires=["events"],
            build=self._build_overview,
        )]

    def _build_overview(self, dash):
        dash.section("Events")
        dash.tile("events.count", by="events.type")

# Use it
analyst = Analyst()
analyst.use(MyConnector(api_key="..."))

Multi-Connector Dashboards

Connectors contribute widgets to shared dashboards:

from dashboardmd import Analyst, Dashboard, Relationship

analyst = Analyst()
analyst.use(project_connector)
analyst.use(team_connector)

# Cross-connector relationship
analyst.add_relationship(Relationship(
    "tasks", "team_members", on=("assignee", "username"), type="many_to_one"
))

# Build unified dashboard with widgets from both connectors
dash = Dashboard(title="Engineering Velocity", analyst=analyst, output="velocity.md")
project_connector.contribute_widgets(dash, ["Project Status"])
team_connector.contribute_widgets(dash, ["Team Overview"])

# Add custom cross-connector analysis
dash.section("Cross-Team Insights")
dash.tile_sql("Hours by Department", """
    SELECT tm.department, SUM(tl.hours) as total
    FROM time_logs tl JOIN team_members tm ON tl.username = tm.username
    GROUP BY 1 ORDER BY 2 DESC
""")

dash.save()

Concept Mapping

Concept Looker PowerBI Cube Metabase dashboardmd
Logical table View Table Cube Table Entity
Attribute dimension Column dimension Column Dimension
Aggregation measure DAX Measure measure Metric Measure
Table link explore + join Relationship joins FK Relationship
Query Explore query Visual query /load API Question Query
Dashboard Dashboard + tiles Report + visuals (frontend) Dashboard + cards Dashboard + Tiles
Integration — — — — Connector

CLI

dashboardmd discover data/          # Auto-discover entities from data files
dashboardmd query data/ "SELECT COUNT(*) FROM orders"   # Run SQL against data
dashboardmd run dashboard.py        # Execute a dashboard script

Development

# Install in development mode
make install

# Run tests
make test

# Run linter + type checker + tests
make check

Project Status

dashboardmd is in early development (v0.1.0). See the design proposal for the full vision and implementation plan.

License

MIT

Metadata

Release files for dashboardmd 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for dashboardmd 0.1.0
File Size Uploaded
dashboardmd-0.1.0.tar.gz 747.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for dashboardmd 0.1.0
File Interpreter ABI Platform
dashboardmd-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 791.8 kB

Release files / dashboardmd-0.1.0.tar.gz

Download URL dashboardmd-0.1.0.tar.gz
Size 747.3 kB
Tags Source
SHA-256 checksum
How to use checksums
271d25ddcd3a7afa152a702d7fccc9f9df0d747386acf80ac486c7335303b20f
BLAKE2b-256 checksum
How to use checksums
8b3d1294eb3104b61483cdee4bdefa25d1406ea30fdb83363d8587ac4fbf6c8e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Mar 13, 2026.

Transparency log

Release files / dashboardmd-0.1.0-py3-none-any.whl

Download URL dashboardmd-0.1.0-py3-none-any.whl
Size 44.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7cbe75f738ee6110977056c74da769c498d9228b5c9d9bb635255882275c9efe
BLAKE2b-256 checksum
How to use checksums
ce4af66579e25ee9a73375cd7538d1b9bd98877d82754a10a6043d3bbb0da0c3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Mar 13, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page