inspect_canvas_libraryfinds the components and templates a block can use.edit_canvas_blockscreates a block or changes a saved one.validate_code_blocksrenders saved blocks in a browser and reports what it saw.inspect_canvas_blocksreads saved blocks.
build-visualizations skill through inspect_skills before you add a Canvas block; it owns design guidance. Page order and block removal belong to edit_pages, and editable model tables to edit_table_blocks.
Find components and templates
Callinspect_canvas_library with a list block whose query is a few search words:
- An entry matches when any one word appears in its title, description, tags, aliases, or decision outcomes.
kindnarrows the list tocomponentortemplate. Withoutquery, the list holds every entry of that kind.
read the entries you plan to use. One read takes up to 16 targets and resolves templates and components together, so a template and the components it needs come back in one call:
read returns each entry’s instructions, its props skeleton, and its runtime requirements. A name that matches nothing, or more than one entry, comes back as an unresolved entry. Library entries are building guidance; they are not saved blocks and prove nothing about how a block renders.
Create a Canvas block
edit_canvas_blocks create requires page, title, and source:
pageis the Page that receives the block, by name or asinspect_pagesprints it.after_blockplaces the block under another one; without it the block goes last.titleis the block’s name. Later updates and page edits name the block by it.- The receipt names the new block two ways.
targetis the block’s name-form selector, which the page and Canvas tools accept wherever they take a block astarget.refis the block’s pasteable reference, such asPipeline by stage#a74, which they accept wherever a result’s block reference is accepted, such asreorder_blocksblock_order. The reference keeps naming the block in lateredit_pagescalls even after a rename. - The receipt also carries
dataset_evidence, one series and one row per dataset as the block receives them, andsource_notes. A dataset still calculating when the result was due is listed withstatus: "unavailable"anderror: this dataset’s calculation had not finished when this result was due, so it was stopped. The block is saved either way, and the other datasets keep their evidence.
What the source must be
source is one complete component, Block({ data, timeSettings, theme, state, action, emit }), run in a sandbox:
- React is injected. Reach hooks through it, such as
React.useState(...); a bareuseState(...)is refused, andwindow.Reactis unavailable. - Imports, network access, and direct AgCharts are forbidden. Custom font families are refused.
print()prints only that block’s frame.- The injected components, their props, and the rest of the runtime contract are in the
sourcefield’s description in the tool schema, and each component’s props ininspect_canvas_libraryread.
Datasets
A dataset is a live, read-only table read that the block receives asdata.<name>. A block holds up to 8.
The block receives the read inverted: each row of the layout becomes a series, and each column becomes one entry of
data.<name>.rows, one plotted point. A layout with columns: [] and window.granularity: "NO_GRANULARITY" declares timeless values: one row holding each Variable’s value.
On update, each datasets entry adds a dataset or replaces the saved one with the same name, and the others stay. Leaving datasets out keeps them all; [] clears them all; remove_datasets removes the ones it names.
Values a dataset row carries
Each row carries each Variable’s own value under its series key:row.date is a display label, and periodStart, when present, is the ISO start of the period. A dataset that failed has empty rows and series and an error string. A comparison dataset also carries scenario.label, scenario.isCurrent, and scenario.lastClose, and timeSettings.lastClose is the current Scenario’s close date or null.
Colors and the theme
- Colors and type from
theme.tokens,theme.design, or--cb-*CSS variables follow the viewer’s light or dark mode. - A literal or named color, including one in a palette, keeps its value in both modes. The write saves it, and the receipt’s
source_notesnames the first one: “<color>on line<n>is the first fixed color in this source: it keeps this value in light and dark mode. Colors from theme.tokens, theme.design, or —cb-* CSS vars follow the viewer’s mode.” - A workspace brand can set the heading typeface, the accent color, and the corner shape. A block follows the brand through
theme.tokens.fontHeadingor--cb-font-heading,theme.tokens.accentor--cb-accent, andtheme.tokens.radiusor--cb-radius, in every workspace it is copied to. source_notesalso flags a component declared insideBlock. React remounts such a component every timeBlockrenders, so a focused input loses focus and its local state resets. Declare components at the top level of the source and pass values through props.
Change a saved block
edit_canvas_blocks update names the block with target, by name, ID, or as inspect_pages prints it. Fields you leave out keep their saved values, and the block keeps its identity and position.
sourcereplaces the whole component.source_patcheschanges part of it: a list of up to 50 exactoldtonewtext replacements, applied in order. Eacholdmust occur exactly once in the source as the earlier patches left it. The block saves only when every patch applies.titlerenames the block; an empty string clears the title.page, when given, confirms the block is still on that Page.
Check that a block renders
A saved block compiles, but only a browser shows whether it renders.- A Canvas write that no browser rendered returns a
render_unverifiedwarning: The block is saved and compiles; whether it renders is proven only when validate_code_blocks opens it in a browser. validate: truebeside the write returns the browser’s result for the saved revision undervalidationinstead. A render check that fails or is unavailable leaves the edit saved. The dataset readback and the render check share one answer deadline, about 10 seconds before the call’s 119-second limit, so the receipt arrives instead of a timeout. If validation has not finished when the result is due,validation.notereads The Canvas edit saved. Browser validation had not finished when this result was due, so it was stopped and the render was not observed. If the result is due before validation begins, it reads The Canvas edit saved. This result was due before browser validation began, so validation did not run and the render was not observed. In both casesvalidation.enabledisfalse, as it is whenever no browser render was observed, including when the check is switched off or unreachable; readvalidation.noteto tell the causes apart. The receipt carries therender_unverifiedwarning, and the saved block stays saved.validate_code_blockschecks saved blocks on their own:
What validate_code_blocks reports
- It renders up to 8 blocks per call in Chromium, with live calculated datasets, once per theme (light and dark). Each render uses the block’s saved state, Scenario, number formats, and Last close, in a frame 1200 px wide. Each result names the revision and source hash it rendered.
- The result’s
observedsentence states what the check saw, such as: “Each block was rendered once per theme, with its saved state, in a 1200 px wide frame. Errors, warnings, plotted chart values, guide anchors, and any visual review come from those renders. Clicks, typing, links, and guide launches did not run, so what they do is unobserved, and the layout at other widths is unseen.” - A block that rendered cleanly carries
plotted: one entry per chart the render drew, withchartnaming the chart by its title, when it has one, and its source position, such asChart "Pipeline" at source L12, andseriesholding one entry per numeric value field of every visible series, withname,count, and thefirst,last,low, andhighplotted points as{x, y}. The values are the ones the chart was given. The chart draws stacked and normalized series, waterfall running totals, and histogram bin counts from them, so the drawn shape of such a series differs from the list. - Errors are failures the render reported: runtime errors, widget errors, a stalled render, console errors, and failed element loads. Warnings may be intended: console warnings, blank or error-code cells, empty or zero-only data, missing series keys, hidden series, and content past the frame’s edge.
- A clean render does not check that the values are financially correct.
guide_targetslists the copyable guide anchors visible in at least one theme, andguideAnchorskeeps each theme’s visibility and ambiguity.guideAnchorslists at most the first 64 distinct anchor IDs per theme, in document order. When the render had more,guide_anchors_cutsays how many, andguide_targetsdraws only on the listed ones.visual_reviewreturns one block in one theme as an image at the frame’s width.
When a render does not happen
Errors a person’s browser reported
When a person’s browser hits a runtime failure while rendering a saved block, it reports the error for that exact Scenario, block, and source revision.inspect_pages read then returns it as the block’s render_error, and a later successful render clears it. An MCP call has no browser of its own, so a block nobody has rendered has no such report. A missing render_error does not mean the block renders.
Read saved Canvas blocks
inspect_canvas_blocks takes target, a block name, ID, or reference, or a list of related blocks, and optionally page to constrain them. It returns each block’s exact saved source, dataset layouts and Scenario bindings, display state, position, revision, and references. All blocks are read at one snapshot, the latest unless as_of_point names an earlier one. It does not calculate datasets, and saved code is no proof of a successful render.
A selection larger than one result is cut short:
- Each run of 1,000 or more encoded characters in a source, such as base64 or hex, reads as
[[N encoded characters not shown]]. - A source still too large comes back in part.
source_partgives the byte range it covers, and the next call passesnext.source_offsetassource_offset. not_returnedlists the selected blocks left out, with their sizes, andnextholds the arguments that read the rest.
Links a block opens
On a user click,emit({type: 'navigate', url}) opens a page or block link that a tool result returned, or another app address in the current workspace, through normal browser history. It keeps Scenario query parameters and #block-anchor-<block-id>. External addresses and public share views are not supported. The source field’s description covers the block’s other actions, such as saving presentation state and starting an Ari action.
Name blocks in page edits
edit_pages arranges and removes blocks, including Canvas blocks.
- A block action names its Page with
page. add_textmay omitpage. It then uses the Page of anafter_blockreference it was given, else the Page in view, else the Scenario’s only Page. When none of these settles it, the call is refused: with several Pages, with no target page and up to 20 of them as candidates, and its hint gives the Scenario’s page count and how many are listed; with no Pages, with this scenario holds no pages.update_textanddelete_blockmay omitpage; they then use the Page in view, and a returned block target finds its own Page.reorder_blocksnames the Page it arranges withpage, or withtarget.block_orderis the complete top-to-bottom order, with each visible block once, by name or by the block references other results print.placemoves one block instead:block,after_block, andto_pageto move it to another Page.- A
delete_blockaimed at a block that another saved change already deleted answersnot_foundand changes nothing. Its message names that change and, when the block went with its Page, the Page:Block <id> is already deleted in scenario "Main": saved change <n> deleted it together with its page "<name>". This call changed nothing.The result carriesblock_id,layer_id, anddeleted_by_change_log_id. delete_blockrefuses to delete objects that lose their last table occurrence while formulas, other blocks, settings, or hand-added items depend on them.force: truedeletes them anyway, and those references break. Objects still shown on other tables are kept.
inspect_pages, see Pagination and truncation.