TableauOps · Free skill

Same prompt. Same model. One had the skill.

A coding agent writing a Tableau viz extension from memory gets the shape right and the details wrong, and the details are the whole job: Tableau either refuses to load the thing or loads it and draws nothing. Both runs are on this page. On the left is what memory produces. On the right is what the skill produces, and it is running live below.

The prompt, given to both runs, word for word

Build me a Tableau viz extension: a dot plot, one field for the category and one for the value. Vanilla JS, no build step, ready to host.

Region filter The filter a real user touches. Watch both panels.
No skill Written from memory 5 of 5 rules missed

Tableau does not say why. Fix the manifest by hand and it loads, and then the failures you cannot see start:

dot-plot.trex
<!-- registers the extension with Tableau -->
<dashboard-extension id="dot-plot" extension-version="1.0.0">
  <name resource-id="name"/>
  <description>Dot plot</description>
  <min-api-version>1.4</min-api-version>
  <source-location>
    <url>https://your.host/dot-plot/index.html</url>
  </source-location>
  <!-- no encodings: nowhere to drop a field -->
</dashboard-extension>
main.js
tableau.extensions.initializeAsync().then(() => {
  // the dashboard API, on a worksheet extension
  const dash = tableau.extensions.dashboardContent.dashboard;
  const ws = dash.worksheets.find(w => w.name === 'Sheet 1');

  // no visual spec: which field is where is a guess
  ws.getSummaryDataAsync().then(d => {
    const rows = d.data;  // one page, silently truncated
    draw(rows.map(r => ({
      item:  r[0].formattedValue,
      value: r[1].value,
    })));
  });
  // drawn once. no SummaryDataChanged listener.
});
With the skill Written with the rules loaded loads first try

Live in this page. Change the region and it redraws, because it listens for the change. Take the fields off and it shows an empty state, not an error.

dot-plot.trex (plus a second one pointing at localhost, for dev)
<!-- registers the extension with Tableau -->
<worksheet-extension id="com.tableauops.dot-plot"
                     extension-version="1.0.0">
  <name resource-id="name"/>
  <description>Dot plot custom mark</description>
  <min-api-version>1.1</min-api-version>
  <source-location>
    <url>https://your.host/dot-plot/index.html</url>
  </source-location>
  <encoding id="item"><display-name>Item</display-name></encoding>
  <encoding id="value"><display-name>Value</display-name></encoding>
</worksheet-extension>
main.js
tableau.extensions.initializeAsync().then(() => {
  const worksheet = tableau.extensions.worksheetContent.worksheet;

  worksheet.addEventListener(
    tableau.TableauEventType.SummaryDataChanged, render);
  render();

  async function render() {
    const spec = await worksheet.getVisualSpecificationAsync();
    const enc = mapEncodings(spec);        // by encoding id
    if (!enc.item || !enc.value)
      return drawEmptyState('Drop a field on Item and Value');

    const reader = await worksheet.getSummaryDataReaderAsync();
    const rows = [];
    for (let p = 0; p < reader.pageCount; p++)
      rows.push(...(await reader.getPageAsync(p)).data);
    await reader.releaseAsync();

    draw(rows, enc);
  }
});

The five rules, and what breaks without each one

Click a row to light it up in both files above. Each one is a real failure with a real fix, and each one is in the skill, so the agent never writes the left column in the first place.

The part that costs you the afternoon

None of these errors are hard. They are invisible, which is worse: Tableau fails quietly, so each one gets found by elimination. Same build, timed twice.

No skill
8:33

Most of it spent working out which of five silent failures was the one in front of you.

With the skill
1:20

Written once, loaded first try, because the rules were in the agent's head before it started.

"The new skill was great. I went from zero to a working dashboard in one initial prompt. I liked some of the standards that were baked in without having to discover them throughout, like creating 2 manifest.trex files for dev and prod."

Michael McCusker, Tableau Tech Lead

"This week I built a viz extension with custom mark types using Eric Summers' Tableau Extensions skill. I gave it one prompt. It built a working extension. I loaded it into Tableau, tested it, and it worked. That was it: one prompt, no error hunting, no second try. The skill did the building. I described what I wanted, and it handled the rest."

Calvin Nguyen, Analytics and Informatics Section Manager, Tableau Certified Architect
See the original post on LinkedIn ↗

The file arrives attached as SKILL.md, ready to drop into .claude/skills/tableau-extensions/ or hand to whatever agent you use. The long version of the pitch is on the skill page. The extensions we already built with it are on the demo page.