Skip to content

Core concepts

Spec vs hand-authored

The YAML spec is how a dashboard is published. The two ways to write your own markup inside it, and why the raw HTML path is closed.

A dashboard reaches Dashies as a spec. Your AI writes a small YAML document naming a connection, a schedule, datasets, and tiles. The server compiles that into the HTML, the data island, and the refresh manifest, and enforces that all three agree.

The raw body path is not available. Uploading finished HTML with its own island and a hand-written manifest is refused. It predates the spec, and the costs of using it are below; dashboards already published that way are unaffected.

Writing your own markup is still supported, INSIDE the spec, and the two ways to do it are below.

What the compiler does for you

When you publish a spec, the server owns three artifacts you never write:

  • the markup, including every data-dash slot and its attributes
  • the data island, seeded with real numbers from your SQL
  • the refresh manifest that the scheduler will re-run

Because it owns all three, it can check them against each other. A tile bound to a measure your query never returns is a publish error naming the exact field. A measure that cannot be re-aggregated in the mode you chose is a publish error. A funnel stage that is not one of the declared values of its dimension is a publish error, because that stage would render as absent rather than as a drop to zero.

None of those are rendering surprises. They are refusals with a pointer at the field, before anything is stored.

What the spec looks like

A complete, minimal one. This publishes as written, against the built-in self connection:

dashies: 1
title: Dashboards published
source:
  connection: self
  schedule: daily
datasets:
  main:
    sql: select day, sum(dashboards_published) as dashboards from dashies_usage_metrics group by day order by day
    dimensions:
      day:
        type: date
    measures:
      dashboards:
        agg: sum
tiles:
  - type: kpi
    measure: dashboards
    title: Dashboards published
  - type: chart
    chart: line
    x: day
    measure: dashboards

Four required keys at the top level: dashies, title, source, and datasets. source needs a connection and a schedule. Each dataset needs sql, dimensions, and measures. Then either tiles or the whole-look escape hatch below, never both.

Note that connection: self is written out. The convenience of omitting it applies to the exploration tools, not to a spec, where leaving it out is a missing-required-property error.

The two ways to write your own markup

Both stay on the spec path, so you keep validation, seeding, and scheduled refresh. You give up only the parts you explicitly opt out of.

Neither is a fallback. A user who wants the dashboard to look a particular way is asking for one of these, and reaching for it is the product working as intended rather than a workaround for something the tiles could not do.

A custom tile

One tile whose HTML and JavaScript you write yourself, reading from named datasets. Everything else on the dashboard stays a managed tile. Use it for a visualization the tile vocabulary does not cover.

Your HTML is mounted verbatim, and your JavaScript runs after the island exists, so it can read the data. A <script> tag inside the custom HTML is inert and produces a warning rather than executing.

The whole-look look field

look replaces the entire page body with HTML you supply, while the datasets, the seeding, and the schedule stay managed. It is mutually exclusive with tiles, and with theme and layout, because it owns the whole page.

The variant worth knowing is look: { from: <slug> }, which references the current published body of the dashboard you are publishing to. That is how you change a dataset or a schedule without re-sending the markup, and how an existing hand-authored dashboard converts to the spec path without its appearance changing by a byte.

The raw body path is not available

Publishing finished HTML with a hand-written manifest is refused. The body, content_type, encoding and source_config arguments are still declared on publish_dashboard, because the path may return in a future version, and each says it is unavailable. Dashboards published that way before are unaffected: they keep serving and keep refreshing on their own contracts, and reading, listing, deleting and restoring them are unchanged.

So the two ways to write your own markup above are the ways: a custom tile, or the whole-look look field. Both stay on the spec path.

The trap the raw path used to be was treating it as the fallback when a spec publish is refused. It never was. A refusal is a bug report with a pointer at the field, and it should be fixed in the spec, the SQL, or the publish arguments. What falling back cost, recorded because it is the argument for the path being closed rather than merely discouraged:

  • You take over hand-maintaining the island and the manifest that the scheduler rewrites, which is where a wrong number becomes permanent.
  • You lose the publish-time structural validation entirely.
  • The whole dataset moves through your AI's context. On the spec path the server runs the query and seeds the rows, so the data never enters the AI's context at all. On the body path the numbers are baked into the bytes the AI sends, so they pass through it twice.

That last point is the practical binding limit. The advertised publish ceiling is 5 MiB, but a real session hit its context wall at around 40 KB of island and spent seven rounds shrinking, dropping a whole dataset, three dimensions, half the time window and most of a detail table to make it fit. If you find yourself deleting real content to make a payload fit, that is the signal to go back to the spec.

Editing a published dashboard

Edit the spec, never the served HTML. A refresh rewrites the island, so a hand-edit to the served bytes is either lost or left inconsistent with the manifest.

Read the stored spec back, change one thing, and republish to the same slug carrying the hash you read. That hash is a lost-update guard: if the stored spec changed since you read it, the publish is rejected and the live dashboard is left untouched, rather than your edit silently overwriting someone else's.

Renaming is a separate operation, not a spec edit. Changing the spec's slug field is refused, because the publish target is the path you publish to; a rename goes through the rename tool, which leaves the old URL redirecting to the new one.

Next

Datasets and the four modes is the decision inside the spec that matters most.