Analyze → chart image
/semilayer analyze <name> turns any analyze you've declared on a
lens into a posted chart image. The platform renders a self-contained
SVG, converts it to PNG server-side, uploads it to a static host, and
posts the URL as a Slack image block or Discord embed image.
A single line in chat → a real chart in the channel. No Console detour, no copy-paste of a query.
What you need first
The analyze block lives in the lens config under analyses.<name>. Same shape the Console + Beam client consume — chat reads from the same registry.
The chat user needs analyze.<name> access. The grants.analyze.<name> field can be public, member, admin, or a list of role names. The chat layer reuses the same RBAC the API uses — no separate "chat permission."
Chart kinds
--kind | Best for |
|---|---|
bar | Default. Categorical comparison. Up to 20 bars; overflow shows "showing N of M". |
line | Time-series with multiple measures. X-axis ordered by your sort. |
area | Same as line but filled. Cumulative metrics. |
donut | Share of whole. Up to 10 slices, rest collapses into "+N more". |
pie | Same as donut but filled center. |
treemap | Hierarchical share. Slice-and-dice layout, up to 30 leaves. |
The renderer picks sensible axis labels, color palette (the SemiLayer
brand gradient), and number formatting (1,234 for counts, $1.2k
for currency-shaped measures).
Public vs ephemeral
Analyze defaults to ephemeral in shared channels (only the typer
sees it) so a casual /semilayer analyze doesn't drown the channel.
When fired by a /semilayer watch … (see below), the result is
always public to the watch's target channel — that's the point.
What gets posted
Slack — header (<analyze name> · <lens>) → image block (the
chart) → context block with the bucket count and a "Open in Console"
deep link.
Discord — embed with title, image attachment, footer with the bucket count, and an Open in Console link in the body.
Click the Open in Console link to drill into the buckets — the same analyze, but with the drill-down UI, sortable table, and per-bucket export.
Watching an analyze
The natural pair to /semilayer analyze is
/semilayer watch analyze — fire that chart automatically every
morning instead of typing the command.
The fired post carries a footer
(🔁 Watch <id> · daily at 09:00 · created by you) so the channel
can spot scheduled posts and stop / pause them with
/semilayer watch stop <id>. See Watch & Remind.
Watched analyzes currently render as a markdown table instead of a chart image — the worker that fires watches does not yet ship the chart-rendering pipeline. You get the bucket data, just rendered differently. Tracked on the chatops roadmap.
Failure modes
"Analyze <name> is not declared on lens <lens>." — The
analyze name doesn't exist on the lens config. Check analyses.<name>
and confirm you pushed the latest config (semilayer push).
"Need more context: lens, project, env." — Scope didn't resolve.
Pass the missing flags explicitly, set them with /semilayer config set, or pin them with /semilayer here set.
"You don't have access to that analyze." — The
grants.analyze.<name> doesn't include your role. Ask an org admin
to update the lens config.
"Analyze took too long — posted as table fallback." — The chart renderer has a 10s budget. If the analyze runs longer (large candidate set, complex aggregation), the markdown-table fallback fires so you still get an answer.
API equivalent
Everything /semilayer analyze does is a thin wrapper over the
platform's analyze API:
The response is the same AnalyzeResult shape the Beam client
returns. The chat layer renders it; the API hands it back as JSON.