Dashboards

A dashboard is the human side of your workspace: a board of cards backed by the same saved actions and Smart Tools your agent uses. Your agent designs it over MCP, you read it in the portal, and nothing on it spends money until you (or a schedule you approved) ask it to.

Let your agent build it

This is the cheap path and the recommended one: the design thinking happens in your agent's own model, so the board costs you nothing to create. Ask for it in plain language and the agent uses create_dashboard, add_widget for each card, refresh_widget to see real data, then update_widget with a card spec tailored to what that data actually looks like. It can theme the whole board from a sentence of intent.

Build me a ToolGlue dashboard for our support queue.
Add a card for open tickets, one for median first response,
and one for the last five escalations. Refresh them, then
tailor each card spec to the real data.

What a card can hold

Ten display blocks (heading, stat, delta, progress, badges, list, spark, text, divider, link) bound to the card's snapshot with $.path expressions, plus four controls: a button, a toggle, a select, and a text input.

A link opens in a new tab and is the one place a card carries a destination, which is why it is display, not a control: it runs nothing and spends nothing. The URL can come straight from a tool's output via a $.path, and a list can link every row the same way with href. Only absolute http(s) destinations ever render as links (anything else shows as plain text), and the destination's host is printed beside the label, so where a click goes is visible before the click.

A control names one of your saved actions or Smart Tools by key and can carry a fixed input. It never carries a URL, a script, or a click handler, because the grammar has nowhere to put one: pressing sends the card and which control you used, and the server reads the tool back out of the stored spec. That is what makes it safe to let an agent design a board with working buttons on it.

{"blocks": [
  {"type": "stat", "label": "Workers", "value": "$.healthy", "format": "number"},
  {"type": "list", "items": "$.incidents", "primary": "$.title", "href": "$.url"},
  {"type": "link", "label": "Open the status page", "url": "https://status.example.com"},
  {"type": "toggle", "label": "Maintenance mode",
   "value": "$.maintenance", "action": "set-maintenance"},
  {"type": "select", "label": "Deploy to", "action": "deploy",
   "options": ["staging", "production"], "confirm": "Deploy now?"},
  {"type": "input", "label": "Ask support", "action": "ask-support",
   "placeholder": "Type a question…"},
  {"type": "button", "label": "Restart worker", "action": "restart-worker",
   "tone": "warning", "confirm": "This restarts the worker. Continue?"}
]}

Every press is a normal billed run, so the price sits on the control before you tap it, and a control can ask for a confirmation first. A toggle binds its state to the data with a $.path rather than remembering the last click, so after it runs, the card refreshes and the switch shows what is actually true. A select dispatches your choice as {"value": "…"} and the server refuses anything not on the option list it re-resolves itself; an input sends your typed text the same way, bounded to 2000 characters. Six controls per card is the cap: each one is a spend somebody has to take in at a glance.

Refreshing, and what it costs

Every card stores its last result, so opening a board is free and always honest about when the data is from. A refresh is a normal billed run of that card's source, priced before you tap it. Refresh one card from the card itself, or use Refresh all to sweep the whole board; the button shows the summed price first. A card whose source fails records the error on itself and the sweep keeps going, so one broken tile never takes the board down.

Auto-refresh on a schedule

A board can refresh itself on a cadence while you are away. Because that is spending money unattended, a schedule never exists without two things beside it: a daily budget it may not cross, and you as the member who approved it. Scheduled runs execute as you, so your own spend limits apply exactly as they would to your tap.

Before each card runs, its price is checked against what is left of the day's budget; the moment the next card would cross it, the board stops and says so on the page. The counter resets at UTC midnight. If the member who approved the schedule leaves the workspace, it turns itself off rather than keep spending on their behalf.

Rules: if this, then that

A rule watches one card and runs after every refresh of it, whether that refresh came from your tap, a sweep, your agent, or the schedule. Point the condition at a value with the same $.path grammar the cards use, pick a comparison (exists, equals, greater than, contains, and so on, plus on error for when the refresh itself fails), and choose what happens: run a saved action, run a Smart Tool, or email you. The action receives a trigger object describing what fired it.

Rules run one hop deep and never trigger each other, so there is no cascade to reason about. Each has a cooldown (five minutes minimum) so a condition that stays true does not turn into a flood, and every firing is recorded on the rule with what it did.

Take it with you

Download PDF renders the board's current snapshots into a report with each card, its data, and when it was last refreshed. It is free: it reads what past refreshes already paid for and runs nothing. Agents can do the same with export_dashboard_pdf and hand you the link.

Something went wrong on our side. Reload ✕
Interactive features couldn't start. The realtime connection is being blocked. If this domain sits behind Cloudflare or a WAF, allow websockets to /_blazor. Retry ✕