TeamDay Docs

Interactive Charts

Embed live charts and data tables in markdown documents using SQL queries or static data. Charts render inline in chat, feed, and file viewer.

Interactive Charts in Documents

TeamDay documents support interactive chart and table blocks that render inline in markdown. Charts can display static data (baked in by the AI agent) or query a live database connection on every view.

TeamDay also renders full Mermaid diagrams from normal mermaid fenced blocks. Use Mermaid for process maps, architecture diagrams, timelines, ER diagrams, sequence diagrams, and other visual explanations that are not better represented as numeric charts.

```mermaid
flowchart LR
  Query[Query data] --> Report[Write Markdown]
  Report --> Chart[Render chart]
  Report --> Diagram[Render Mermaid]
```

Chart Block Syntax

Chart blocks use fenced code blocks with a special language annotation:

```data
[{"category":"Hiking","revenue":45000},{"category":"Running","revenue":62000}]
```

The annotation format is: source:blockType(param=value, param="value with spaces")

Sources

SourceDescription
dataStatic data embedded in the block. The AI bakes numbers in when writing the report.
sqlLive read-only PostgreSQL query against an org data connection. Runs server-side when someone views the document.

Block Types

TypeDescription
chartRenders a Chart.js visualization (bar, line, pie, etc.)
tableRenders a formatted data table with headers and rows

Parameters

ParameterRequiredDescription
typechart onlyChart type: bar, line, pie, doughnut, area
titlenoDisplay title above the chart/table
connectionsql onlyName of the org data connection. production-db resolves to an org secret such as TEAMDAY_DATA_CONNECTION_PRODUCTION_DB_URL.
cachenoCache duration: 30s, 5m, 1h, none. Default: 5m

Static Charts (data:chart)

Static charts contain their data directly in the block body as JSON. The AI agent computes or fetches the data during the conversation, then writes it into the markdown file.

Array of Objects

The simplest format — an array of objects where the first key becomes the x-axis label and remaining keys become data series:

```data
[
  {"region": "Europe", "revenue": 145000, "orders": 2340},
  {"region": "Americas", "revenue": 98000, "orders": 1560},
  {"region": "Asia", "revenue": 67000, "orders": 890}
]
```

This renders a bar chart with "Europe", "Americas", "Asia" as labels and two series: "revenue" and "orders".

Labels + Datasets Format

For more control, use the structured format with explicit labels and named datasets:

```data
{
  "labels": ["Jan", "Feb", "Mar", "Apr", "May", "Jun"],
  "datasets": [
    {"label": "Revenue", "values": [45000, 48000, 52000, 51000, 58000, 63000]},
    {"label": "Costs", "values": [32000, 33000, 34000, 33500, 35000, 36000]}
  ]
}
```

Live SQL Charts (sql:chart)

SQL charts query a database connection every time the document is viewed. The query runs server-side with caching.

```sql
SELECT DATE_TRUNC('month', created_at) as month,
       COUNT(*) as orders
FROM orders
WHERE created_at > NOW() - INTERVAL '12 months'
GROUP BY 1
ORDER BY 1
```

Column Mapping

The SQL result columns map to chart axes automatically:

  • First column = labels (x-axis)
  • Remaining columns = data series (y-axis)
  • Column names become series labels in the legend
SELECT month,    revenue,   cost,    profit
--     ^ labels  ^ series1  ^ series2 ^ series3
FROM monthly_summary
ORDER BY month

Connection Name

The connection parameter maps to an organization secret that stores a PostgreSQL URL. For example, connection=production-db looks for:

  1. TEAMDAY_DATA_CONNECTION_PRODUCTION_DB_URL
  2. PRODUCTION_DB_DATABASE_URL
  3. PRODUCTION_DB_URL

The database user in that URL should be read-only. TeamDay also enforces a server-side read-only transaction, accepts only SELECT / WITH queries, applies a 5 second statement timeout, and caps results at 1,000 rows.

Plain sql fenced blocks render as SQL code examples. Executable SQL-backed report blocks must use sql:chart(...) or sql:table(...).

Caching

Live queries are cached server-side to avoid hitting the database on every page view:

ValueDuration
30s30 seconds
5m5 minutes (default)
1h1 hour
noneNo caching, always fresh

Charts display a "cached" indicator when serving cached data.

Data Tables (sql:table / data:table)

Tables work the same way as charts but render as formatted HTML tables instead of visualizations:

```sql
SELECT product_name,
       SUM(quantity) as units_sold,
       SUM(revenue) as revenue
FROM order_items
GROUP BY product_name
ORDER BY revenue DESC
LIMIT 10
```

Static data tables:

```data
[
  {"team": "Engineering", "headcount": 12, "budget": "$1.2M"},
  {"team": "Marketing", "headcount": 5, "budget": "$400K"},
  {"team": "Sales", "headcount": 8, "budget": "$600K"}
]
```

Tables automatically:

  • Format numbers with commas (e.g., 45,000)
  • Show null values as "—"
  • Highlight rows on hover
  • Indicate when results are truncated (>1,000 rows)

Chart Types

Bar Chart

Best for comparing categories. Use when you have discrete categories on the x-axis.

type=bar

Line Chart

Best for trends over time. Use when the x-axis represents a time series.

type=line

Area Chart

Like a line chart with the area filled. Good for showing volume or cumulative data.

type=area

Pie / Doughnut Chart

Best for showing composition or parts of a whole. Use with a single data series.

type=pie
type=doughnut

Where Charts Render

Chart blocks render in these surfaces:

SurfaceStatic (data:)Live (sql:)
Chat messagesYesYes
File viewer / editor previewYesYes
Feed previewYesYes

The feed shows truncated text previews. Click through to the full document to see rendered charts.

Teaching Your Agent

To have your AI agent write reports with charts, include the chart syntax in the agent's system prompt or as a skill. Example instruction:

When writing reports with data, embed charts using this syntax:

  ```data
  [{"label": "...", "value": ...}, ...]

For live dashboards, use SQL chart blocks:

SELECT ...

Available chart types: bar, line, pie, doughnut, area Available connections: production-db, analytics-db


## Limitations

- **Read-only queries** — INSERT, UPDATE, DELETE, DROP, and other mutations are blocked
- **5-second timeout** — queries that take longer are cancelled
- **1,000 row limit** — results exceeding this are truncated
- **PostgreSQL only** for live queries — MySQL, BigQuery, and others coming soon
- **No cross-database joins** — each chart block queries a single connection

## API Reference

The chart blocks use the [Connections Query API](/api/connections) under the hood. You can call it directly for programmatic access.