← Port Agent Skills (EU)CONTENT HISTORY

Update to Port Agent Skills (EU)

Snapshot Oct 28, 2026 · 13:15 UTC · version 1.0.8

Collection source: downloaded plugin package.

WHAT CHANGED

First saved snapshot

No earlier snapshot is available to establish a change.

Save Port Agent Skills (EU) and check future changes in Following.

Up to 10 plugins free · no card required.

Compare saved observations

Download comparison JSON
Full technical diff · 0 changed fields
Full snapshot data
{
  "description": "Build and update Port dashboard pages: widgets (table, number chart, pie chart, bar chart, multi-line chart, markdown, iframe, links, action card, action-runs table, entity details, AI agent), the 12-column row layout, sidebar placement, and private-page rules. Covers dataset filter syntax so a widget shows the entities you expect instead of an empty or wrong result. Use when asked to \"build a Port dashboard\", \"add a widget to a dashboard page\", \"create a number chart / pie chart / table widget in Port\", \"why is my Port widget empty\", \"make this dashboard page private\", or \"where should this dashboard go in the sidebar\". For building a custom plugin widget (your own React iframe), use the nested `port-dashboard-plugins` skill instead.",
  "included_files": [
    {
      "relative_path": "port-dashboard-plugins/SKILL.md",
      "size_in_bytes": 20095
    },
    {
      "relative_path": "port-dashboard-plugins/assets/template-App.css",
      "size_in_bytes": 6657
    },
    {
      "relative_path": "port-dashboard-plugins/assets/template-App.tsx",
      "size_in_bytes": 2031
    },
    {
      "relative_path": "port-dashboard-plugins/assets/template-README.md",
      "size_in_bytes": 6166
    },
    {
      "relative_path": "port-dashboard-plugins/assets/template-config.ts",
      "size_in_bytes": 1912
    },
    {
      "relative_path": "port-dashboard-plugins/assets/template-index.html",
      "size_in_bytes": 249
    },
    {
      "relative_path": "port-dashboard-plugins/assets/template-index.tsx",
      "size_in_bytes": 428
    },
    {
      "relative_path": "port-dashboard-plugins/assets/template-package.json",
      "size_in_bytes": 951
    },
    {
      "relative_path": "port-dashboard-plugins/assets/template-resolveHostEntity.ts",
      "size_in_bytes": 859
    },
    {
      "relative_path": "port-dashboard-plugins/assets/template-tsconfig.json",
      "size_in_bytes": 256
    },
    {
      "relative_path": "port-dashboard-plugins/assets/template-types.ts",
      "size_in_bytes": 944
    },
    {
      "relative_path": "port-dashboard-plugins/assets/template-upload-params.json",
      "size_in_bytes": 107
    },
    {
      "relative_path": "port-dashboard-plugins/assets/template-usePostMessageData.ts",
      "size_in_bytes": 2657
    },
    {
      "relative_path": "port-dashboard-plugins/assets/template-useScrollMirror.ts",
      "size_in_bytes": 2205
    },
    {
      "relative_path": "port-dashboard-plugins/assets/template-webpack.config.js",
      "size_in_bytes": 1761
    },
    {
      "relative_path": "port-dashboard-plugins/assets/webpack/lodash-root-shim.js",
      "size_in_bytes": 343
    },
    {
      "relative_path": "references/dashboards.md",
      "size_in_bytes": 19310
    }
  ],
  "name": "port-dashboards",
  "skill_md_contents": "---\nname: port-dashboards\ndescription: >-\n  Build and update Port dashboard pages: widgets (table, number chart, pie\n  chart, bar chart, multi-line chart, markdown, iframe, links, action card,\n  action-runs table, entity details, AI agent), the 12-column row layout,\n  sidebar placement, and private-page rules. Covers dataset filter syntax so\n  a widget shows the entities you expect instead of an empty or wrong\n  result. Use when asked to \"build a Port dashboard\", \"add a widget to a\n  dashboard page\", \"create a number chart / pie chart / table widget in\n  Port\", \"why is my Port widget empty\", \"make this dashboard page private\",\n  or \"where should this dashboard go in the sidebar\". For building a custom\n  plugin widget (your own React iframe), use the nested\n  `port-dashboard-plugins` skill instead.\nlicense: MIT\ncompatibility: \"Claude Code, Cursor, Codex CLI, GitHub Copilot\"\nmetadata:\n  version: \"1.0.0\"\n  author: port-labs\n  repository: https://github.com/port-labs/port-skills\n  tags: port,dashboards,widgets,reference\n  summary: Build Port dashboard pages with widgets, layout, and permissions\n---\n\n# Port dashboard pages\n\nA Port dashboard page is a sidebar entry made of one or more widgets (tables,\ncharts, markdown, links, and more) arranged in a 12-column grid. This skill\nis reference-only: static knowledge about widget schemas, the layout grid,\nsidebar placement, and dataset filter syntax, drawn from Port's dashboard\npage schema and public docs. It doesn't need a live Port account or MCP\nserver to produce a correct dashboard payload, only a real account to\nactually create the page.\n\nOut of scope: building your own custom-code widget (a React/TypeScript\niframe plugin uploaded via `port-plugins-cli`) is the nested\n[`port-dashboard-plugins`](port-dashboard-plugins/SKILL.md) skill, not this\none. Blueprint and property modeling (what a `dataset` can filter on) is\nowned by the `port-blueprints` skill; this skill only covers how those\nproperties map onto widget and dataset fields. The full search rule\ngrammar (all operators, `and`/`or`/`not` nesting) is Port's [Search and\nquery](https://docs.port.io/search-and-query/structure-and-syntax) syntax;\nthis skill covers the subset relevant to widget datasets. Who can **view or\nedit** a page once it exists, including private pages shared with specific\nusers or teams, is the `port-permissions` skill's page-permissions\nreference, not this one; this skill only covers a private page's own\ncreation and visibility mechanics (see [Step 5](#step-5---handle-private-pages-correctly)).\n\n## Skill class\n\nReference skill: the widget schemas, grid rules, and dataset syntax below\nare static and enough to hand-author a correct dashboard JSON payload. If\nthe [Port MCP server](https://docs.port.io/ai-interfaces/port-mcp-server/overview)\nis connected, its dashboard tools (`upsert_dashboard_page`, `upsert_widget`,\n`get_page`, `get_sidebar`, `load_widget_schema`, `list_entities`,\n`list_blueprints`) are an optional enhancement: they create the page for\nyou and let you sample real entities to validate a dataset before saving.\nWithout them, use the fallback in every step below: the Port UI's dashboard\neditor, or the [Pages API](https://docs.port.io/api-reference/pages) /\n[Swagger](https://api.port.io/swagger/#Pages) directly.\n\n## Prerequisites\n\n- Go over the `port-getting-started` skill first if this is your first time\n  working with Port.\n- The blueprint(s) the dashboard's widgets will query already exist, with\n  the properties you plan to filter, group, or chart on.\n- Optional: the Port MCP server connected in your agent, for live dataset\n  validation and one-shot page creation (see Skill class above). Without\n  it, use the Port UI or the Pages API with a `client_id`/`client_secret`\n  pair (**...** menu > **Credentials** in the Port app). Search\n  `search_port_knowledge_sources` for anything this skill doesn't cover.\n\n## Step 1 - Decide sidebar placement\n\nPrecondition: a new dashboard page needs a home in the sidebar.\nAction: if MCP is available, call `get_sidebar` to inspect the existing\nfolder structure before creating the page. If a single folder clearly\nmatches the dashboard's topic, place the page there (`parent` on the page).\nIf several folders are plausible, ask the user which one they prefer\ninstead of guessing. If nothing matches, place the page at the sidebar\nroot, creating a new folder only when the dashboard starts a new category\nof its own.\nFallback: without MCP, open the Port UI's sidebar and read the folder tree\ndirectly, or `GET /v1/pages` (see [references/dashboards.md](references/dashboards.md#sidebar-placement-and-page-fields))\nto list existing pages and their `parent`/`after` fields.\n\n## Step 2 - Choose widgets and validate each dataset\n\nPrecondition: you know which entities and metrics the dashboard should\nshow.\nAction: pick one widget type per metric or view from the twelve types in\n[references/dashboards.md](references/dashboards.md#widget-types), matching the widget to the question\n(\"how many\" -> number chart, \"trend over time\" -> multi-line chart, \"browse\nrows\" -> table). For every widget with a `dataset`, resolve the target\nblueprint first, then validate the dataset **before** creating the widget:\nif MCP is available, run `list_entities` with the dataset as `query`,\n`countOnly: true`, and a small `limit` (3-5), to confirm the count and that\nthe returned entities look right. If the call errors or the results look\nwrong, call `list_blueprints` to check property names, types, and enum\nvalues, fix the dataset, and retry.\nFallback: without MCP, run the equivalent call yourself:\n`POST /v1/blueprints/{blueprint}/entities/search` with the same `query`\nbody (see [references/dashboards.md](references/dashboards.md#dataset-filter-syntax) for the rule\ngrammar and examples), or build the widget in the Port UI and use its\nbuilt-in entity count/preview before saving.\n\n## Step 3 - Lay out the page (12-column grid)\n\nPrecondition: the widget set for the page is known.\nAction: arrange widgets into rows. Every row's column sizes must sum to\nexactly 12, a row holds at most 4 columns, each column is 3-12 wide, and\nevery row is at least 400px tall. Every layout column's `id` must match a\nwidget's `id` exactly, one-to-one. See\n[references/dashboards.md](references/dashboards.md#the-12-column-layout-grid) for the layout\nschema and worked examples.\nFallback: the Port UI's drag-and-drop dashboard editor enforces these\nconstraints for you, use it when hand-writing a layout for 6+ widgets gets\nerror-prone.\n\n## Step 4 - Create or update the page\n\nPrecondition: widgets and layout are ready.\nAction: if MCP is available, call `upsert_dashboard_page` with the full\n`identifier`, `title`, `widgets`, and `layout`. For 5+ widgets, try the full\npayload first; if it fails on size or complexity, fall back to an\nincremental flow: create an empty page (`widgets: []`), add widgets one at\na time with parallel `upsert_widget` calls, then call `get_page` and pass\nits `widgets` straight through to a final `upsert_dashboard_page` call that\nonly adds the new `layout`.\nFallback: without MCP, create the page from the Port UI's dashboard editor,\nor call the [Pages API](https://docs.port.io/api-reference/pages) directly:\n`POST /v1/pages` (or `PATCH /v1/pages/{identifier}` if it already exists)\nwith `type: \"dashboard\"` and a single root `dashboard-widget` wrapping your\n`widgets` and `layout` (see\n[references/dashboards.md](references/dashboards.md#creating-a-page-with-the-raw-api) for the exact\nenvelope Port expects).\n\n## Step 5 - Handle private pages correctly\n\nPrecondition: the dashboard is personal, not for the whole organization.\nAction: set `visibility: \"private\"` and omit `parent` and `after`\nentirely, whether via MCP or the raw API. Port keeps private pages in a\nseparate sidebar section and appends an owner-specific suffix to the\nidentifier in its response, use *that* returned identifier for any\nfollow-up edit, widget update, or delete, not the one you sent.\nFallback: from the UI, set **Visibility** to **Private** when creating the\npage (the field is read-only after creation for non-admins); an org admin\nmust first grant the `create:private-pages` scope if the option isn't\nvisible. See [references/dashboards.md](references/dashboards.md#private-pages) for the full\nrules and an example payload.\n\n## Examples\n\nWorked, complete JSON payloads for every widget type, a full layout, and\nthe raw API envelope are in\n[references/dashboards.md](references/dashboards.md#widget-types).\n\n## Common pitfalls\n\n| Symptom | Cause | Fix |\n|---|---|---|\n| Widget renders empty or with the wrong entities | Dataset filters on the wrong property, wrong blueprint, or a typo'd enum value | Validate with `list_entities`/`entities/search` before creating the widget, see [Step 2](#step-2---choose-widgets-and-validate-each-dataset) |\n| Page creation rejected: \"column sizes must sum to 12\" | A row's column `size` values don't add to 12 | Recompute the row, max 4 columns, each 3-12 wide, see [Step 3](#step-3---lay-out-the-page-12-column-grid) |\n| Page creation rejected: row height too small | A row's `height` is under 400px | Set every row to at least 400 |\n| Widget never renders / layout looks broken | A layout column's `id` doesn't match any widget's `id` | Keep widget `id`s and layout column `id`s in exact sync |\n| Private page edits silently target the wrong page, or 404 | Used the `identifier` you sent instead of the one Port returned (owner-suffixed) | Store and reuse the identifier from the create/`get_page` response, see [Step 5](#step-5---handle-private-pages-correctly) |\n| Private page creation rejected | `parent` or `after` was set alongside `visibility: \"private\"` | Omit both fields entirely for private pages |\n| Number chart shows 0 or an error | `chartType`-specific required fields missing (e.g. `func`/`averageOf` for `aggregateByProperty`) | Check the per-`chartType` required fields in [references/dashboards.md](references/dashboards.md#number-chart-entities-number-chart) |\n| Pie/bar chart property rejected | `property` isn't prefixed (`property#`, `relation#`, `scorecard#`, ...) or a meta field (`$identifier`, `$title`, `$team`) | Use the prefixed form, see [references/dashboards.md](references/dashboards.md#property-reference-syntax) |\n\n## Quick reference\n\n- Widget types: `table-entities-explorer`, `entity-details`,\n  `action-card-widget`, `action-runs-table-widget`, `links-widget`,\n  `ai-agent`, `markdown`, `iframe-widget`, `entities-number-chart`,\n  `entities-pie-chart`, `bar-chart`, `multi-line-chart`. Full schema for\n  each: [references/dashboards.md](references/dashboards.md#widget-types).\n- Layout: rows of 1-4 columns, column `size` 3-12 summing to exactly 12 per\n  row, row `height` >= 400px, column `id` matches a widget `id`.\n- Visibility: `\"org\"` (default, sidebar-placeable via `parent`/`after`) or\n  `\"private\"` (no `parent`/`after`, identifier gets an owner suffix).\n- Dataset shape: `{ combinator: \"and\" | \"or\", rules: [...] }`, each rule a\n  `property`/`relation`/`scorecard` clause. Full grammar:\n  [references/dashboards.md](references/dashboards.md#dataset-filter-syntax).\n- MCP tools (optional, live account): `get_sidebar`, `list_blueprints`,\n  `list_entities`, `load_widget_schema`, `upsert_widget`,\n  `upsert_dashboard_page`, `get_page`.\n- Fallback without MCP: Port's UI dashboard editor, or the\n  [Pages API](https://docs.port.io/api-reference/pages) (`POST`/`PATCH`/`GET`\n  `/v1/pages`) and `POST /v1/blueprints/{blueprint}/entities/search` for\n  dataset checks.\n- For custom-code widgets instead of built-in widget types, see the nested\n  [port-dashboard-plugins](port-dashboard-plugins/SKILL.md) skill.\n"
}

SHA-256 of public snapshot: b1a5651f2d6f96c3f5141ff16ab364d1aa8a396ee97ad20cd979b1c535fa20da