Tableau spec
Skill laviDrori0702/tableau-dashboard-creator-skill/skills/tableau-spec
Translates the approved HTML mock (mock.html) into an IMPLEMENTATION-SPEC.md for the tableau-dashboard-plugin workflow, mapping every mock element to a concrete Tableau construct so the build step never has to guess. Reconciles coverage the mirror of the mock's checklist so nothing is left unmapped, and applies a simplest-primitive guard defaulting each element to the simplest sufficient Tableau primitive and forcing an explicit justification for any escalation to an advanced feature (Dynamic Zone Visibility, LOD, table calculation, parameter action), so the workbook is not over-engineered. Emits a required Layout section (a fenced JSON container tree with canvas dimensions, nested vert/horz containers, and percentage sizes) so the build reproduces the mock's geometry instead of guessing it. Reads the approved mock.html and DASHBOARD-PLAN.md. Use when the user wants to write the implementation spec, map the mock to Tableau, or when tableau-route reports spec is next. Step 7 of 8 in the workflow.From its SKILL.md
npx -y skills add laviDrori0702/tableau-dashboard-creator-skill --skill tableau-specAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 20 stars20 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
9.6 KB, as published. Nobody here has run it
tableau-spec
Step 7 of 8, and non-skippable. It turns the approved mock.html into an
IMPLEMENTATION-SPEC.md that maps every mock element to a concrete Tableau construct,
so tableau-build builds from an explicit spec instead of guessing. It ends with a
coverage reconciliation — the mirror of the mock's checklist — proving every mock
element is mapped, and applies a simplest-primitive guard so the workbook uses the
simplest construct that does the job.
| Reads | Required: mock-version/<v_N>/mock.html (from mock) — the elements to map, tagged with data-plan-id; and DASHBOARD-PLAN.md (from plan) — the shared element/filter/interaction ids and the interaction intents (CONTRACT.md §6). |
| Writes | mock-version/<v_N>/IMPLEMENTATION-SPEC.md — a standalone deliverable copy (CONTRACT.md §4.3). |
| STATE.md update | Sets spec = approved; flips a downstream approved build step to stale on a re-run (CONTRACT.md §4.2). Does not touch current_version — only tableau-mock bumps it (§4.3). |
| Entry gate | Refuses to run until plan is resolved and DASHBOARD-PLAN.md exists, and mock is resolved and mock.html exists at current_version (CONTRACT.md §4.1). |
| Next step | tableau-build (or tableau-route to confirm). |
The mechanical guarantees — the entry gate, the coverage reconciliation (every mock
element mapped, nothing unmapped), the simplest-primitive guard (any advanced feature
carries a justification), the version bump, and the STATE.md transition — live in
spec.py (CLI) and reconcile.py (the reconciliation + guard core). Your job is the
judgment part: choosing the right, simplest Tableau construct for each element and
justifying any escalation. Run the script at the points below; do not hand-edit STATE.md.
The two conventions the reconciliation depends on
reconcile.py decides "mapped" and "laid out" mechanically, so the spec must carry a
single Element Mapping table and a Layout section (see
references/IMPLEMENTATION-SPEC-TEMPLATE.md):
- The table's first column header is
idand it has a column whose header containsconstructand one whose header containsjustif. - One row per mock element, with the
idmatching adata-plan-idfrommock.htmlexactly. A mock id with no row is an unmapped element that blocks approval — this is what makes "nothing unmapped" a guarantee. - The construct cell names the Tableau construct; the justification cell explains
any escalation (leave it blank /
-for a simple primitive). - The
## Layoutsection holds a short summary and a fenced JSON container tree derived from the approved mock: the mock'scanvasdimensions, nestedvert/horzcontainers, and element-id leaves with percentagesizes (siblings sum to ~100). Every mapped zone id appears exactly once; interaction ids (int-*) are actions, not zones, and never appear. This is how the mock's geometry reachestableau-build— a missing or inconsistent Layout blocks approval exactly like an unmapped element. - Siblings meant to stay equal must be a container's only children. Tableau holds a row of equal cards equal by distributing the container evenly, so an equal group stranded beside a smaller sibling (three chart cards above a 3% legend strip) cannot be held — the build pins every child but the biggest, and the group drifts apart on any dashboard taller than its minimum. Wrap the group in its own container; the validator flags this.
The simplest-primitive guard
Default every element to the simplest sufficient Tableau primitive. Only escalate to an advanced feature when the simpler option genuinely cannot do the job — and when you do, write why in the justification cell (what simpler alternative you rejected and the concrete reason). The guard flags these advanced features when their justification is blank:
| advanced feature | simpler default to justify against |
|---|---|
| Dynamic Zone Visibility (DZV) | a show/hide button container |
LOD expression ({FIXED ...}) | a plain aggregate (SUM, AVG) or the view's default grain |
table calculation (WINDOW_*, RUNNING_*, INDEX(), RANK) | a native aggregate or quick table calc on the view |
| parameter action | a filter action / highlight action, or a static parameter |
The concrete "what's simplest for this interaction" knowledge lives in the validated
snippet library. Map the shared interaction terms to their simplest construct first
(CONTRACT.md §6): cross-filter → a Filter action (Use as Filter); highlight → a
Highlight action; drill → a hierarchy expand/collapse; swap view / toggle panel / parameter swap → these legitimately need DZV / parameter — justify them.
How to run
-
Precheck. From the project directory, run:
python "${CLAUDE_SKILL_DIR}/scripts/spec.py" precheck "<project-dir>"(Use
python3ifpythonis unavailable.) If it prints[BLOCKED], relay the reason and stop — the analyst must resolve the named upstream step (tableau-mockfor the approved mock,tableau-planfor the blueprint) first. Otherwise note its signals: the mock path to map from, the list of element ids every one of which needs a mapping row, and the target path to writeIMPLEMENTATION-SPEC.mdinto (the mock'scurrent_version— spec writes beside themock.htmlit maps and never bumps the version). -
Read the inputs. Read
mock.htmlat the reported mock path — itsdata-plan-idattributes are your exact mapping list. ReadDASHBOARD-PLAN.mdfor what each id is (KPI / chart kind / filter / interaction) and the interaction intents, so you map to the right construct. -
Author
IMPLEMENTATION-SPEC.mdat the precheck's target path. Fill the Element Mapping table with one row per mock element, defaulting to the simplest primitive and justifying every escalation. Write the## Layoutsection by reading the mock's actual geometry (its rows, columns, and nesting) into the JSON container tree — sizes as percentages of the parent, canvas from the plan's Screen Size. Add the supporting detail the build needs (calculated fields, data source / joins, actions, parameters) following the template. When refining an existing spec at this version,Editit in place. -
Self-check, then present. Validate the draft before showing it:
python "${CLAUDE_SKILL_DIR}/scripts/spec.py" validate "<project-dir>"It prints the reconciliation checklist (one line per mock element, each
[x]mapped or[ ]unmapped / unjustified-escalation), the guard result, and the layout check (the container tree present and consistent with the mapping). If it prints[INVALID], map the missing element(s) / add the missing justification(s) / fix the named layout problem(s) and re-run. When it prints[OK], show the checklist to the analyst (it's the proof nothing was dropped and nothing is over-engineered) and present the spec for approval. -
Commit — only after the analyst approves:
python "${CLAUDE_SKILL_DIR}/scripts/spec.py" commit "<project-dir>"Commit re-runs the full reconciliation + guard (spec is non-skippable, so it only ever sets
approved). If it prints[REFUSED], fix what the checklist names and re-run. On success it recordsspec=approved, setscurrent_versionto the targetv_N, and reports any downstream step it markedstale. Relay the summary and tell the analyst to open a fresh conversation and run the next step (tableau-build, ortableau-routeto confirm).
Notes
- Non-skippable. The build needs an explicit spec;
commitonly ever setsapproved. - Versioned deliverable.
IMPLEMENTATION-SPEC.mdlives undermock-version/<v_N>/beside itsmock.html(CONTRACT.md §4.3). Spec writes into the mock'scurrent_versionand overwrites in place on a re-run; it never bumpscurrent_version. A new spec version is created by re-runningtableau-mock(which bumps and stales spec). The target path is reported byprecheck.
The full
STATE.mdschema and the ordering / staleness / versioning rules live inCONTRACT.mdat the repo root. This skill restates only its own slice;spec.py/reconcile.pyare the executable mirror of the contract it enforces.