Generated banner for Dashboard Expert
Generated logo for Dashboard Expert

Dashboard Expert

OpenAIOfficialCreated by MixpanelDistributed by OpenAI

  • Skill
  • Tool integration
  • Data and AI
  • MIT
  • No issues found

From the author

Full CRUD and analysis for Mixpanel dashboards. Use when the user asks to build, create, analyze, read, understand, explain, modify, update, enhance, or manage dashboards, or asks about dashboard layout, text cards, or report arrangement. Covers dashboard analysis (read + understand existing), creation (new builds), modification (update existing), and explanation (data-driven annotation).
— the description by Mixpanel

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

Dashboard Expert provides a comprehensive framework for interacting with Mixpanel dashboards. It supports four primary modes: analyzing existing dashboards to extract insights, building new dashboards from scratch, modifying existing layouts or content, and adding data-driven annotations to provide context. The skill emphasizes a structured workflow, ensuring that data is investigated before building, and that modifications follow strict API ordering requirements to maintain dashboard integrity.

What it does

  • Analyzes dashboard structure and executes underlying reports to synthesize findings.
  • Builds new dashboards by planning layouts and querying metrics.
  • Modifies existing dashboards by adding, reordering, or deleting content.
  • Annotates dashboards with data-driven text cards to provide context.
  • Validates data availability before creating new reports.
  • Ensures correct API operation ordering for dashboard updates.

When to use it

  • When you need to understand the performance metrics displayed on a dashboard.
  • When creating a new dashboard to track product health or specific user behaviors.
  • When updating an existing dashboard to include new metrics or improve layout.
  • When you need to add explanatory text to clarify data trends for stakeholders.

Advantages

  • Provides a consistent, repeatable process for dashboard management.
  • Reduces errors by enforcing correct API operation sequences.
  • Enables data-driven insights through automated report execution and summarization.
  • Supports complex layout management including row and cell organization.

Usage examples

“Analyze the Product Health dashboard and summarize the key trends.”
The agent will read the dashboard structure, execute all contained reports, and provide a summary of metrics, trends, and cross-report correlations.
“Create a new dashboard for tracking signup conversion.”
The agent will investigate relevant events, propose a layout, and build a new dashboard with appropriate funnel and insight reports.
“Add a text card to the top of my dashboard explaining the recent drop in DAU.”
The agent will analyze the current dashboard, generate an insightful text card based on the data, and insert it into the layout.

Install

  1. Download the skill as a ZIP:

    https://mp-staging.autogineer.com/agent-skills/openai/dashboard-expert/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip dashboard-expert.zip -d .agents/skills

Documentation by Mixpanel

Dashboard Expert

Analyze, build, modify, and explain Mixpanel dashboards. Four modes — pick the one matching the user's intent.

Mode Selection

User intentModeKey actions
"analyze/understand/read/explore dashboard"AnalyzeRead structure, execute reports, summarize
"build/create/make a new dashboard"BuildInvestigate data → plan → create with layout
"modify/update/add to/fix/improve dashboard"ModifyRead current state → plan changes → execute
"explain/annotate/add insights to dashboard"ExplainAnalyze → generate data-driven text cards

Quick Start: Analyze an Existing Dashboard

import json, re
import mixpanel_headless as mp

ws = mp.Workspace()
dash = ws.get_dashboard(DASHBOARD_ID)
layout, contents = dash.layout, dash.contents

# Extract structure: rows → cells → content items
for row_id in layout["order"]:
    row = layout["rows"][row_id]
    for cell in row["cells"]:
        cid, ctype = str(cell["content_id"]), cell["content_type"]
        if ctype in ("report", "report-link"):
            info = contents["report"][cid]
            print(f"  [{cell['width']}w] {info['name']} ({info['type']}) {'[linked]' if ctype == 'report-link' else ''}")
        elif ctype == "text":
            md = contents["text"][cid].get("markdown", "")
            is_header = bool(re.search(r'<h2[\s>]', md, re.I))
            print(f"  [{cell['width']}w] TEXT {'[SECTION]' if is_header else ''}: {md[:60]}...")

# Execute each report → DataFrame
for cid, info in contents.get("report", {}).items():
    btype, bid = info["type"], info["id"]
    if btype == "flows":
        result = ws.query_saved_flows(bid)
    else:
        result = ws.query_saved_report(bid, bookmark_type=btype)
    df = result.df
    print(f"{info['name']}: {len(df)} rows, columns={list(df.columns)}")

Quick Start: Build a New Dashboard

from mixpanel_headless.types import CreateDashboardParams, DashboardRow, DashboardRowContent
import json

ws = mp.Workspace()
dau = ws.query("Login", math="dau", last=90)

def text(html):
    return DashboardRowContent(content_type="text", content_params={"markdown": html})

def report(name, btype, result):
    return DashboardRowContent(content_type="report", content_params={
        "bookmark": {"name": name, "type": btype, "params": json.dumps(result.params)}})

dashboard = ws.create_dashboard(CreateDashboardParams(
    title="Product Health", description="Core metrics.",
    rows=[
        DashboardRow(contents=[text("<h2>Product Health</h2><p>Core metrics.</p>")]),
        DashboardRow(contents=[report("DAU (90d)", "insights", dau)]),
    ],
))
ws.pin_dashboard(dashboard.id)  # Make visible to team

Mode: Analyze

Read existing dashboards, execute their reports, and synthesize understanding.

Phase A1: Read Dashboard Structure
dash = ws.get_dashboard(dashboard_id)
layout, contents = dash.layout, dash.contents

Parse the response into a structured representation:

  • layout["order"] — ordered list of row IDs

  • layout["rows"][row_id]["cells"] — cells with content_id, content_type, width

  • contents["report"][str(content_id)] — report metadata: id (bookmark_id), name, type, params, description

  • contents["text"][str(content_id)] — text card: markdown

Classify each cell:

  • content_type == "report" → owned, editable

  • content_type == "report-link" → linked from another dashboard, read-only

  • content_type == "text" → text card; detect section headers via re.search(r'<h2[\s>]', md, re.I)

Build a mental model: Group reports by section (text cards with <h2> tags delimit sections). Note each report's chart type, width, and position.

Phase A2: Extract Report Details

For deeper understanding, fetch full bookmark params:

bookmark = ws.get_bookmark(bookmark_id)
params = bookmark.params  # Full query definition dict

Key fields in params (Insights format):

  • params["sections"]["show"] — metrics with event names and math type

  • params["sections"]["group"] — breakdown properties

  • params["sections"]["filter"] — active filters

  • params["sections"]["time"] — date range

  • params["displayOptions"]["chartType"] — visualization type

Note: params in contents["report"][id] may be a JSON string — parse with json.loads() if needed.

Phase A3: Execute and Summarize

Execute each report to get live data:

for cid, info in contents.get("report", {}).items():
    bid, btype = info["id"], info["type"]
    if btype == "flows":
        result = ws.query_saved_flows(bid)
    else:
        result = ws.query_saved_report(bid, bookmark_type=btype)
    df = result.df

Summarize by report type:

TypeKey metrics to extract
insightsTotal, average, latest value, min, max, trend direction
funnelsStep names, counts, per-step and overall conversion rate
retentionDay 1, Day 7, Day 30 rates; stabilization point
flowsTop paths, conversion rate, drop-off points

Cross-correlate across reports: Look for relationships — DAU trends vs. retention, funnel drop-off vs. feature adoption.

Phase A4: Present Analysis

Structure findings as:

  1. Dashboard overview — title, purpose, section count, report count

  2. Section-by-section breakdown — what each section measures, key findings

  3. Cross-metric insights — correlations, anomalies, patterns

  4. Suggestions — missing metrics, better chart types, layout improvements

Multi-Dashboard Analysis

When analyzing multiple dashboards, build a unified picture:

dashboard_ids = [1001, 1002, 1003]
all_data = {}
for did in dashboard_ids:
    dash = ws.get_dashboard(did)
    for cid, info in dash.contents.get("report", {}).items():
        result = ws.query_saved_report(info["id"], bookmark_type=info["type"])
        all_data[f"{dash.title}/{info['name']}"] = result.df
# Cross-dashboard: join DataFrames on date index, compute correlations

Mode: Build

Create new dashboards from scratch. Five phases.

Phase B1: Investigate

Before building, discover the data. Never build reports for events with zero volume.

ws = mp.Workspace()
top = ws.top_events(limit=15)
for t in top:
    print(f"{t.event}: {t.count:,} ({t.percent_change:+.1%})")

# Validate candidate events
for event in candidate_events:
    result = ws.query(event, from_date="2025-01-01", to_date="2025-03-31")
    print(f"{event}: {result.df['count'].sum():,.0f} total")

# Explore properties for breakdowns
props = ws.properties(event="key_event")
values = ws.property_values(event="key_event", property="platform", limit=20)
Phase B2: Plan Structure

Present a proposed structure before building. Choose a template from references/dashboard-templates.md.

A plan includes: title + description, sections with text card headers, reports per section with chart type, grid layout.

Text cards use HTML (not markdown). Every dashboard must have an intro text card and section headers.

Allowed HTML tags: <h1>, <h2>, <h3>, <p>, <strong>, <em>, <u>, <s>, <mark>, <code>, <blockquote>, <hr>, <br>, <ul>, <ol>, <li>, <a href="...">

Forbidden (stripped): <div>, <span>, <b> (use <strong>), <i> (use <em>), <img>, <table>

Critical: Strip \n and collapse whitespace from HTML before sending. Each element renders as its own line.

Text card patterns:

Intro:     <h2>Dashboard Title</h2><p>What and why. Time period: last 90 days.</p>
Section:   <h2>Acquisition</h2><p>How users discover and sign up.</p>
Explainer: <p>^ Signup conversion is <strong>23.4%</strong>, up 2.1pp.</p>
Phase B3: Query and Build

Query each metric, verify data, then create with layout in one call.

def text(html):
    return DashboardRowContent(content_type="text", content_params={"markdown": html})

def report(name, btype, result, description=None):
    params = {"bookmark": {"name": name, "type": btype, "params": json.dumps(result.params)}}
    if description:
        params["bookmark"]["description"] = description
    return DashboardRowContent(content_type="report", content_params=params)

dashboard = ws.create_dashboard(CreateDashboardParams(
    title="Product Health Dashboard",
    description="Key metrics for product health monitoring.",
    rows=[
        DashboardRow(contents=[text("<h2>Product Health</h2><p>Updated daily.</p>")]),
        DashboardRow(contents=[
            report("DAU (90d)", "insights", dau),
            report("Signups (90d)", "insights", signups),
            report("Revenue (90d)", "insights", revenue),
        ]),
        DashboardRow(contents=[text("<h2>Conversion</h2><p>Key funnels.</p>")]),
        DashboardRow(contents=[report("Signup Funnel", "funnels", funnel)]),
    ],
))

On report failure, substitute a fallback text card:

try:
    result = ws.query(event, math="total", last=90)
    row_items.append(report(f"{event} Trend", "insights", result))
except Exception as e:
    row_items.append(text(f"<p><strong>Failed:</strong> {event} — {e}</p>"))
Phase B4: Enhance
  • Pin for team visibility: ws.pin_dashboard(dashboard.id) — dashboards are invisible by default

  • Favorite for personal use: ws.favorite_dashboard(dashboard.id)

  • Add explainer cards: see Mode: Explain

  • Adjust heights: see references/dashboard-reference.md Section 3.4

Phase B5: Verify

Open the dashboard and confirm all reports render with data, text cards display correctly, and layout matches the plan.


Mode: Modify

Update existing dashboards. Read first, then apply changes in the correct order.

Phase M1: Read Current State

Use Analyze Phase A1-A2 to understand the dashboard's structure. Present to user before making changes.

Phase M2: Plan Changes

Classify each change and plan execution order. Operations must follow this sequence:

  1. Metadata (title/description) — standalone PATCH

  2. Cell creates — add new content first

  3. Row reorder (rows_order) — after creates so temp IDs resolve

  4. Cell updates — modify existing content

  5. Cell deletes — remove content

  6. Row deletes — remove entire rows last

Phase M3: Execute Changes

Adding content to a specific existing row — send content AND layout together:

import copy
dash = ws.get_dashboard(dashboard_id)
layout = copy.deepcopy(dash.layout)
target_row = layout["rows"][target_row_id]

# Redistribute widths
new_count = len(target_row["cells"]) + 1
cell_width = 12 // new_count
for cell in target_row["cells"]:
    cell["width"] = cell_width
target_row["cells"].append({"temp_id": "-1", "width": cell_width})

ws.update_dashboard(dashboard_id, UpdateDashboardParams(
    content={"action": "create", "content_type": "report",
             "content_params": {"bookmark": {"name": "New Report", "type": "insights",
                                              "params": json.dumps(result.params)}}},
    layout={"rows_order": layout["order"], "rows": layout["rows"]},
))

Adding content as a new row — content action alone (appends to bottom):

ws.update_dashboard(dashboard_id, UpdateDashboardParams(
    content={"action": "create", "content_type": "text",
             "content_params": {"markdown": "<p>^ Explainer card.</p>"}},
))

Deleting content:

ws.update_dashboard(dashboard_id, UpdateDashboardParams(
    content={"action": "delete", "content_type": "report", "content_id": content_id},
))

Cross-type updates (e.g., text → report): API rejects changing content_type on update. Delete the old cell, then create the new one.

See references/dashboard-reference.md Section 8 for temp ID resolution, operation ordering details, and report-link semantics.


Mode: Explain

Combine analysis with targeted text card insertion.

  1. Analyze — run Mode: Analyze to extract structure and execute reports

  2. Generate insights — for each report, compute key metrics from the DataFrame:

    latest = df.iloc[-1]["count"]
    prev = df.iloc[-8]["count"]
    trend = ((latest - prev) / prev) * 100
    html = (f"<p>^ DAU is <strong>{latest:,.0f}</strong>, "
            f"{'up' if trend > 0 else 'down'} <strong>{abs(trend):.1f}%</strong> "
            f"vs. last week.</p>").replace("\n", "")
  3. Insert cards — add as new rows below each report section:

    ws.update_dashboard(dashboard_id, UpdateDashboardParams(
        content={"action": "create", "content_type": "text",
                 "content_params": {"markdown": html}},
    ))

Critical Gotchas

  1. Combined content+layout PATCH — send both content and layout in the same UpdateDashboardParams to add cells to specific existing rows. Without layout, new content appends as a full-width row at the bottom.

  2. Width auto-redistribution — when adding to an existing row with N cells, set all cells (including new) to 12 // (N+1) width.

  3. Update operation ordering — metadata → cell creates → rows_order → cell updates → cell deletes → row deletes. Wrong order causes failures.

  4. per_user requires math_property — using per-user aggregation without a numeric property raises BookmarkValidationError.

  5. CreateBookmarkParams(dashboard_id=X) does NOT add to layout — use add_report_to_dashboard() or inline content action.

  6. add_report_to_dashboard() CLONES — creates "Duplicate of..." copy. Use rows in CreateDashboardParams or inline content action instead.

  7. GET order vs PATCH rows_order — layout from GET uses order; PATCH expects rows_order.

  8. Never include version in layout PATCH — the API rejects it.

  9. Strip \n and collapse whitespace — call .replace("\n", "").strip() on text card HTML. Newlines cause TipTap to mangle content.

  10. Limits — title 255 chars, description 400 chars, text cards 2,000 chars, max 4 items/row, max 30 rows.

  11. Cross-type cell updates require delete+create — API rejects changing content_type on an update action.

  12. Report-link cells are read-only — content_type: "report-link" references a report owned by another dashboard. You can view but not edit its params.

  13. Auto-pin after creation — dashboards are invisible to the team by default. Call ws.pin_dashboard(dashboard.id).

  14. The markdown field accepts only HTML — despite the name. Markdown syntax renders as literal text.

See Also

  • references/dashboard-reference.md — Complete API reference, layout system, content actions, text card formatting, update operations, analysis patterns

  • references/dashboard-templates.md — 9 purpose-built dashboard templates with section layouts and report specs

  • references/bookmark-pipeline.md — End-to-end pipeline from typed query to dashboard report for all 4 engines

  • references/chart-types.md — Chart type selection guide with slugs, use cases, and width recommendations

Files

references/bookmark-pipeline.md

Bookmark Pipeline Reference

How typed query results become dashboard reports. Every query method returns a result with a .params dict ready for CreateBookmarkParams -- no manual JSON construction needed.

All code examples use the mixpanel_headless Python library.

import mixpanel_headless as mp
from mixpanel_headless.types import (
    CreateBookmarkParams,
    CreateDashboardParams,
    UpdateDashboardParams,
)

ws = mp.Workspace()

The Pipeline

Every engine follows the same four steps:

  1. Query -- Call a typed query method to get data.

  2. Inspect -- Check the result (.df for DataFrame, raw attributes).

  3. Save -- Create a bookmark with CreateBookmarkParams using result.params.

  4. Place -- Add the bookmark to a dashboard.

The key advantage: .params is generated automatically by the typed query methods. The dict contains the exact bookmark parameters Mixpanel needs. You never construct bookmark JSON by hand.


Engine 1: Insights

# 1. Query
result = ws.query("Login", math="dau", group_by="platform", last=90)

# 2. Inspect
print(result.df.describe())
print(f"Total: {result.df['count'].sum():,.0f}")

# 3. Save as bookmark
# Assumes `dashboard` was created earlier via ws.create_dashboard(...)
bookmark = ws.create_bookmark(CreateBookmarkParams(
    name="DAU by Platform (90d)",
    bookmark_type="insights",
    params=result.params,
    description="Daily active users segmented by platform.",
    dashboard_id=dashboard.id,
))

# 4. Place on dashboard
ws.add_report_to_dashboard(dashboard.id, bookmark.id)

Key parameters: events (str or list), math ("total", "dau", "wau", "mau", etc.), group_by, where (Filter), last (days, default 30), from_date/to_date.


Engine 2: Funnels

# 1. Query
result = ws.query_funnel(
    steps=["Page View", "Signup Started", "Signup Completed", "First Action"],
    from_date="2025-01-01",
    to_date="2025-03-31",
)

# 2. Inspect
print(result.df)
for step in result.steps:
    print(f"  {step['name']}: {step['count']:,}")

# 3. Save as bookmark
bookmark = ws.create_bookmark(CreateBookmarkParams(
    name="Signup Conversion Funnel",
    bookmark_type="funnels",
    params=result.params,
    dashboard_id=dashboard.id,
))

# 4. Place on dashboard
ws.add_report_to_dashboard(dashboard.id, bookmark.id)

Key parameters: steps (list of str, min 2), conversion_window (default 14), conversion_window_unit, order ("loose" or "any"), group_by, where, last/from_date/to_date.


Engine 3: Retention

# 1. Query
result = ws.query_retention(
    born_event="Signup",
    return_event="Login",
    from_date="2025-01-01",
    to_date="2025-03-31",
    alignment="birth",
)

# 2. Inspect
print(result.df)
print(f"Average retention: {result.average:.1%}")

# 3. Save
bookmark = ws.create_bookmark(CreateBookmarkParams(
    name="New User Retention (D1-D30)",
    bookmark_type="retention",
    params=result.params,
    dashboard_id=dashboard.id,
))

# 4. Place on dashboard
ws.add_report_to_dashboard(dashboard.id, bookmark.id)

Key parameters: born_event, return_event, retention_unit ("day", "week", "month"), alignment ("birth" or "calendar"), bucket_sizes (custom intervals), last/from_date/to_date.


Engine 4: Flows

# 1. Query
result = ws.query_flow(
    event="Signup",
    forward=5,
    count_type="unique",
    from_date="2025-01-01",
    to_date="2025-03-31",
)

# 2. Inspect
print(result.df.head())  # Top paths

# 3. Save
bookmark = ws.create_bookmark(CreateBookmarkParams(
    name="Post-Signup User Journeys",
    bookmark_type="flows",
    params=result.params,
    dashboard_id=dashboard.id,
))

# 4. Place on dashboard
ws.add_report_to_dashboard(dashboard.id, bookmark.id)

Key parameters: event (str), forward (steps after, default 3), reverse (steps before, default 0), count_type ("unique", "total", "session"), collapse_repeated, last/from_date/to_date.


Alternative: Inline Report Creation

Create reports directly on dashboards without creating separate bookmarks. This is the preferred method -- no cloning, no "Duplicate of ..." prefix, single API call.

import json

# Query any engine
result = ws.query("Login", math="dau", last=30)

# Create report directly on dashboard
ws.update_dashboard(dashboard.id, UpdateDashboardParams(
    content={
        "action": "create",
        "content_type": "report",
        "content_params": {
            "bookmark": {
                "name": "Daily Active Users",
                "type": "insights",
                "params": json.dumps(result.params),
                "description": "DAU over the last 30 days.",
            }
        },
    }
))

With inline creation, params must be a JSON string (json.dumps(result.params)), not a dict. This is the most common mistake. The bookmark API accepts a dict; the inline content action accepts a JSON string.


Bookmark Types

Enginebookmark_type valueQuery method
Insights"insights"ws.query()
Funnels"funnels"ws.query_funnel()
Retention"retention"ws.query_retention()
Flows"flows"ws.query_flow()

Common Mistakes

1. Wrong bookmark type string
# WRONG -- singular
bookmark_type="funnel"
bookmark_type="flow"

# CORRECT -- plural for funnels, plural for flows
bookmark_type="funnels"
bookmark_type="flows"
2. Forgetting json.dumps() for inline creation
# WRONG -- dict for inline content action
"params": result.params

# CORRECT -- JSON string for inline content action
"params": json.dumps(result.params)

Note: CreateBookmarkParams.params accepts a dict. Only inline content actions need json.dumps().

3. Expecting dashboard_id to place the report
# WRONG -- this associates metadata, does NOT add to the layout
ws.create_bookmark(CreateBookmarkParams(
    name="Report",
    bookmark_type="insights",
    params=result.params,
    dashboard_id=dashboard.id,  # required, but does not place on layout
))
# You must ALSO call add_report_to_dashboard() or use inline creation
4. Not inspecting data before saving
# WRONG -- save without checking
bookmark = ws.create_bookmark(CreateBookmarkParams(...))

# CORRECT -- verify the query returned meaningful data
result = ws.query("Login", math="dau", last=30)
if result.df.empty:
    print("No data -- skipping this report")
else:
    bookmark = ws.create_bookmark(CreateBookmarkParams(
        name="DAU", bookmark_type="insights",
        params=result.params, dashboard_id=dashboard.id,
    ))
5. Using wrong parameter names from other APIs
# WRONG -- these are not the actual parameter names
ws.query_funnel(events=["A", "B"])       # parameter is "steps", not "events"
ws.query_flow(from_event="A", steps=5)   # parameter is "event" and "forward"
ws.query_retention(retention_type="birth")  # parameter is "alignment"

End-to-End: Multi-Engine Dashboard

A complete example building a dashboard with one report from each query engine.

import json
import mixpanel_headless as mp
from mixpanel_headless.types import (
    CreateDashboardParams,
    UpdateDashboardParams,
)

ws = mp.Workspace()

# Create the dashboard
dashboard = ws.create_dashboard(CreateDashboardParams(
    title="Product Overview",
    description="Key metrics across all analytics dimensions.",
))

# Add intro text card
ws.update_dashboard(dashboard.id, UpdateDashboardParams(
    content={
        "action": "create",
        "content_type": "text",
        "content_params": {
            "markdown": (
                "<h2>Product Overview</h2>"
                "<p>Key metrics across all analytics dimensions.</p>"
            )
        },
    }
))

# Query all 4 engines
dau = ws.query("Login", math="dau", last=30)
funnel = ws.query_funnel(
    steps=["Signup", "Onboarding", "First Action"],
    last=90,
)
retention = ws.query_retention(
    born_event="Signup",
    return_event="Login",
    last=90,
)
flows = ws.query_flow(
    event="Signup",
    forward=5,
    last=30,
)

# Add each report inline (preferred -- no cloning, no separate bookmarks)
reports = [
    ("Daily Active Users", "insights", dau),
    ("Signup Funnel", "funnels", funnel),
    ("New User Retention", "retention", retention),
    ("Post-Signup Journeys", "flows", flows),
]

for name, btype, result in reports:
    if result.df.empty:
        print(f"Skipping {name} -- no data")
        continue
    ws.update_dashboard(dashboard.id, UpdateDashboardParams(
        content={
            "action": "create",
            "content_type": "report",
            "content_params": {
                "bookmark": {
                    "name": name,
                    "type": btype,
                    "params": json.dumps(result.params),
                }
            },
        }
    ))

print(f"Dashboard created: {dashboard.id}")

This creates a dashboard with 5 items: one text card header and four reports, one from each query engine. All reports use inline creation to avoid cloning artifacts.

Requirements and compatibility

Written for: OpenAI Codex

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Needs: Declares allowed tools, Needs Python

Security

No issues found by our static scan· No issues found

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Created by
Mixpanel
Publisher
OpenAI (Official)
Distributed by
OpenAI
Source
openai/plugins · plugins/mixpanel-headless/skills/dashboard-expert · commit d420d13
Licence
MIT License (redistribution allowed)
  • LICENSE (added by AutoGineer from plugins/mixpanel-headless/LICENSE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by Mixpanel or OpenAI.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download dashboard-expert.zip