Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsCommunityBlog
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

Back to skills

Coupler Live Artifact

ASecurity

Build a live Cowork artifact (persistent HTML widget) backed by a Coupler.io dataflow. Use this skill whenever the user wants a live dashboard, persistent widget, daily-check page, or interactive explorer over Coupler.io data — including phrases like "live artifact for Coupler", "Coupler dashboard widget", "build a widget over a Coupler dataset", "Coupler.io live dashboard", "build a daily dashboard from a Coupler dataflow", or any time they ask to render Coupler data in a re-openable view th...

33 stars
0 votes
0 copies
0 views
Added 9/19/2026
datarustgosqltesting

Works with

mcp

Security Analysis

A100/100

Scanned 9/19/2026

Install to Claude Code

$npx -y skills add coupler-io/skills --skill coupler-live-artifact --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Coupler Live Artifact?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Coupler Live Artifact
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/coupler-io-coupler-live-artifact/badge)](https://www.skillsdirectory.com/skills/coupler-io-coupler-live-artifact)

More formats (shields.io, HTML) on the badges page.

Download Zip
Files
SKILL.md
---
name: coupler-live-artifact
description: Build a live Cowork artifact (persistent HTML widget) backed by a Coupler.io dataflow. Use this skill whenever the user wants a live dashboard, persistent widget, daily-check page, or interactive explorer over Coupler.io data — including phrases like "live artifact for Coupler", "Coupler dashboard widget", "build a widget over a Coupler dataset", "Coupler.io live dashboard", "build a daily dashboard from a Coupler dataflow", or any time they ask to render Coupler data in a re-openable view that auto-refreshes. Triggers even when the user does not say "skill" or "artifact" but describes the same outcome (e.g. "I want a page I can check every morning that pulls my Coupler data").
metadata:
  category: utilities
  sources: []
---

# Coupler.io live artifact

A live artifact is a self-contained HTML page registered with Cowork that persists across sessions and re-fetches data from MCP connectors every time it opens. This skill covers the specific pitfalls of wiring one to a Coupler.io dataflow. Most generic widget guidance (CDN allowlist, sandboxing) lives in Cowork's `create_artifact` tool description — read that first. This skill captures the Coupler-specific traps that cost real time the first time someone hits them.

## When to use

The user wants a re-openable view over Coupler.io data: KPIs, funnel, leaderboard, time series, comparison. They have an existing dataflow or are pointing at a data set in their Coupler workspace. The output is a `.html` file registered via `mcp__cowork__create_artifact`.

## Process

### Step 1 — Probe in chat first

Before writing a single line of HTML, run these chat-side calls and read the output. All Coupler operations go through the single dispatcher tool `coupler`: `coupler({verb: "call", name: "<operation>", args: {...}})`. Args are snake_case.

1. `search-datasets({query: "<dataflow name>"})` to find the `dataflow_id`, `last_dataset_snapshot_id`, and the dataset `id`.
2. `get-schema({dataset_snapshot_id})` and **read `ai_context` carefully**. It documents column meanings, the funnel order, the SQL conventions, and known caveats. Most pitfalls are flagged here.
3. `get-data({dataset_snapshot_id, query: "SELECT * FROM data LIMIT 3"})` to see the actual row shape. Confirm what the schema claims.
4. `get-data({dataset_snapshot_id, query: "SELECT DISTINCT col_X FROM data ORDER BY col_X"})` for any column you intend to expose as a filter dropdown — pre-compute the full enum.
5. **Verify the stated grain.** The schema's `ai_context` often claims one row per `(entity × time)`, but real data sometimes has finer grain. Run:
   ```sql
   SELECT col_<id>, col_<time>, COUNT(*) cnt FROM data GROUP BY col_<id>, col_<time> HAVING cnt > 1 LIMIT 5
   ```
   If this returns rows, the grain is finer than advertised — the leaderboard query must `GROUP BY <id>` and `SUM(...)` everything, otherwise duplicates show up.

Read `references/coupler-conventions.md` once before writing SQL. It encodes Coupler's column/value conventions you will hit immediately.

### Step 2 — Decide the refresh strategy

Two modes, pick by how stale the user can tolerate:

| Mode | Behavior | Latency | When to use |
|---|---|---|---|
| **Live snapshot** (default) | Each artifact open calls `list-datasets({dataflow_id})`, takes `last_dataset_snapshot_id`, queries with `get-data`. | Fast (~1 RTT). | Daily checks, dashboards, any case where the user is fine with the last scheduled run. |
| **Forced refresh** (button) | Manual button calls `run-dataflow({dataflow_id})`, polls `list-datasets` every 5 s for up to 5 min until snapshot ID changes, then re-queries. | 30 s – several min. | "I want fresh data right now" buttons. Never on every page load — too slow and wasteful. |

Default to live-snapshot for load. Add a "Refresh data" button for forced refresh. Show `last_success_run_at` ("Last run: 5h ago") in the header so the user knows how stale things are.

### Step 3 — Pick widget MCP tools

Only list MCP tools you actually call from the widget in the `mcp_tools` parameter of `create_artifact`. There is a single Coupler tool — the dispatcher — but **its exact name is specific to this Cowork installation and must never be hardcoded.** Find it yourself: look through your own available tools for the one matching `mcp__<connector-id>__coupler`, where `<connector-id>` is a UUID tied to this installation's registered Coupler MCP connector. Every installation has a different UUID — a skill that ships a literal one will silently call a tool name that doesn't exist anywhere else.

- Whatever you find, list it once in `mcp_tools`; it covers all operations.

Widget-side calls take the form:

```js
window.cowork.callMcpTool("<your discovered mcp__<connector-id>__coupler tool name>",
  { verb: "call", name: "list-datasets", args: { dataflow_id: DATAFLOW_ID } })
```

Operations the widget uses: `list-datasets` (snapshot lookup — accepts `dataflow_id` alone), `get-data` (runs SQL), `run-dataflow` (only if a refresh button exists).

Do **not** use:
- `search-datasets` with only `dataflow_id` — its validator rejects this and returns "At least one of query, source, or name must be provided".
- `get-dataflow` for snapshot lookup — it returns config (sources/destinations) only, no snapshot ID.

### Step 4 — Write the artifact HTML

Start from `references/widget-template.html` — it's a minimal working scaffold with the right boilerplate (Chart.js CDN tag, snapshot lookup, `localStorage` filter persistence, light-mode styling).

Required helpers (in `references/snippets.js`, copy-paste into the artifact):

1. **Tolerant MCP response parser.** Widget-side `callMcpTool` wraps results inconsistently — sometimes direct JSON, sometimes `{content:[{type:"text",text:"..."}]}`, sometimes prose-prefixed text like `"Total datasets: 1\n\n[...]"`. Use the snippet's `parseToolResult` + `tryJsonFromText` — they handle all variants.
2. **Timezone-safe month strings.** Never use `new Date(y, m, 1).toISOString().slice(0, 10)` — for users east of UTC it returns the previous day, silently producing zero-row queries. Use the snippet's `monthFirst` / `prevMonthFirst`.
3. **Quote stripping.** Coupler stores string columns with embedded double quotes (e.g. `col_1 = '"Looker Studio"'`). SQL `WHERE` matches must include the quotes; display layer must strip them. Use the snippet's `stripQuotes` for display, and quote values in SQL like `col_1 = '"${value}"'`.
4. **Run-and-poll.** If the widget has a refresh button, copy the snippet's `refreshData` flow.
5. **Chart.js canvas wrapping.** With `responsive: true, maintainAspectRatio: false`, every `<canvas>` must sit inside a parent with explicit height (e.g. `<div style="position:relative;height:260px;width:100%"><canvas/></div>`). Without it, Chart.js silently collapses the canvas and renders a broken-image icon.
6. **Allowed CDN libs only.** Chart.js, Grid.js, Mermaid — exact tags from Cowork's `create_artifact` description (with `integrity` and `crossorigin`). Anything else must be inlined.
7. **`localStorage` for filter/sort state.** Persist the user's dropdown selections and sort order between opens — that's what makes a daily-check view feel right.

### Step 5 — Verify in the widget runtime

Probing in chat verifies data shape but **not** widget-runtime behavior. The two failure modes that are invisible to chat-side testing:

- **MCP-wrapper shape differences** — same tool returns one shape in chat, another shape (often prose-prefixed text) in widgets.
- **Timezone bugs** — `new Date(...).toISOString()` behaves differently per user, and the symptom is silent zeros, not an error.

After registering the artifact, verify the rendered widget shows non-zero values for a known-populated month. If KPIs all read 0, suspect the timezone bug or the quote convention before suspecting the data.

### Step 6 — Register the artifact

```
mcp__cowork__create_artifact({
  id: "<kebab-slug>",
  html_path: "<absolute path to the .html in outputs>",
  description: "<one-line summary of what it shows>",
  mcp_tools: ["<your discovered mcp__<connector-id>__coupler tool name, from Step 3>"]
})
```

For updates: `mcp__cowork__update_artifact({id, html_path, update_summary})`. Include a real `update_summary` — it's shown to the user in the approval prompt.

## Rules & Edge Cases

- **Always read `ai_context` from `get-schema` before writing SQL.** It documents column quote conventions, the funnel order, and known caveats. Skipping this step is the most common time-waster.
- **Verify dataset grain with a `GROUP BY ... HAVING COUNT(*) > 1` probe.** Don't trust the schema's stated grain. If the real grain is finer than advertised, your leaderboard will show duplicates.
- **Never hardcode `dataset_snapshot_id`.** It rotates on every dataflow run. Always resolve via `list-datasets({dataflow_id})` (through the dispatcher) at load time.
- **Default to live-snapshot loads, gate `run-dataflow` behind an explicit button.** Triggering a fresh run on every artifact open turns a 1-second load into a 1-minute load. Users will hate it.
- **Coupler's string-quoting convention is not stable.** Some dataflows/snapshots store strings with embedded double quotes (`col_X = '"Looker Studio"'`), others do not (`col_X = 'Looker Studio'`). The convention can flip between snapshots of the same dataflow. Always probe `SELECT * FROM data LIMIT 1` and look at the actual values before writing SQL filters. Defense in depth: write filters that match both conventions, e.g. `col_X IN ('value', '"value"')`. Keep `stripQuotes` on the display layer as a no-op safety net.
- **Build YYYY-MM-01 strings manually.** Never via `toISOString()`. Use `${y}-${String(m+1).padStart(2,"0")}-01`. The timezone bug is silent — it produces zero-row queries, not errors.
- **Chart.js canvases need a fixed-height parent.** Wrap every `<canvas>` in `<div style="position:relative;height:Npx;width:100%">`. Otherwise canvases collapse to 0 and you get a broken-image fallback.
- **Only the CDN libs listed in the `create_artifact` tool description load.** Chart.js, Grid.js, Mermaid. Use the exact `<script>` tags including `integrity` and `crossorigin`. Other CDNs are blocked.
- **The widget runs in light mode.** Set `:root { color-scheme: light }` and use a light background with dark text.
- **All Coupler operations go through the `coupler` dispatcher.** `mcp_tools` lists only the dispatcher tool; widget calls pass `{verb: "call", name, args}` with snake_case args. The operation set can change — discover via `{verb: "tools"}` rather than trusting memory. The dispatcher's widget-runtime response wrapping has not been end-to-end verified; the tolerant parser in `references/snippets.js` is designed to absorb extra wrapping, but the first artifact built against the dispatcher must complete the Step 5 verification.
- **`mcp_tools` array must list every tool the widget actually calls** (for Coupler, that is just the dispatcher). Tools not listed will fail at runtime.
- **Filter dropdown values: pre-compute, don't query in the widget.** Pulling distinct values is slow and pointless when you already know the enum at build time.
- **End-to-end widget verification is not optional.** Probe-in-chat catches data-shape bugs but misses widget-wrapper and timezone bugs. Always reload the rendered widget once and confirm non-zero values for a known-populated period.
- **`table-layout: fixed` collapses `auto`-width columns when other columns sum near the table width.** If a column needs to be flexible but visible, give it an explicit width (e.g. `280px`), not `auto`. Wrap the table in `overflow-x:auto` as a fallback.

## Reference files

- `references/coupler-conventions.md` — Coupler quote convention, grain caveats, ai_context tips, MCP tool quirks. Read before writing SQL.
- `references/snippets.js` — Drop-in helpers: `parseToolResult`, `tryJsonFromText`, `monthFirst`, `prevMonthFirst`, `stripQuotes`, `runQuery`, `fetchSnapshotInfo`, `refreshData`. Copy what you need into the artifact.
- `references/widget-template.html` — Minimal working scaffold (snapshot lookup, KPI cards, Chart.js, localStorage state, refresh button). Start here for new artifacts.

## Self-improvement

When the user flags a new Coupler quirk or widget-runtime gotcha, append it to `Rules & Edge Cases`. When the user approves a finished artifact that demonstrates a useful pattern (e.g. a clean way to render a stacked-bar funnel with destination breakdown), copy it to `references/examples/<descriptive-name>.html` for future runs to anchor on.

Attribution

coupler-iocoupler-io
View sourceMore from coupler-io →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Rank Tracker

This skill helps you track, analyze, and report on keyword ranking positions over time. It monitors both traditional SERP rankings and AI/GEO visibility to provide comprehensive search performance insights.

1821 votes

Youtube Competitor Analyzer

Find and analyze YouTube competitor channels using YouTube Data API v3. Discover competitors through keyword search, category matching, content similarity, and related channel discovery. Compare metrics, content strategies, and market positioning. Use when users want to (1) Find competitors for their YouTube channel, (2) Analyze competitor performance metrics, (3) Compare their channel against competitors, (4) Identify content gaps and opportunities, (5) Benchmark against similar creators, (6...

31 votes

Twitter Algorithm Optimizer

Analyze and optimize tweets for maximum reach using Twitter's open-source algorithm insights. Rewrite and edit user tweets to improve engagement and visibility based on how the recommendation system ranks content.

742580 votes

Weather Fetcher

Instructions for fetching current weather temperature data for Karachi, Pakistan from wttr.in API

655280 votes

Weather

Get current weather and forecasts (no API key required).

476190 votes
View all in data →