Skip to content
Skills Library
AI & agents · Building & coding

pmstack-custom-view

/pmstack-custom-view

Makes Eval Studio draw each trace the way the user saw it when no built-in view fits. Chooses between a panel layout in the product setup and a custom view file in pmstack/renderers/, writes it, and confirms it renders in the studio. Use when traces look like raw fields in Review traces, or when the product's output is not a chat, text message, phone call, email, document, answer with sources, agent steps, code review, form fields, or ranked list.

Repository
pmstack ↗
Licence
MIT
Last repository change
24.09.2026

Assessment and security

100/ 100Class: good
Format25 / 25
Frontmatter with name and description, valid name, description up to 1,024 characters, name matching the folder.
Discoverability25 / 25
Description explains when to use the skill, has a reasonable length and uses third person.
Content35 / 35
At least 150 words and at most 500 lines, headings, step lists, examples or code.
Hygiene15 / 15
No placeholders such as TODO, no Windows paths, with a licence.
Riskno signals detected in the scan
Files in this package
1
Scripts
0
HTML comments
0
URLs in SKILL.md
2
Deprecation

No signals detected. Repository changed on 24.09.2026, without references to retired models or APIs.

Licence

MIT, open: use and modify while retaining author attribution.

What it does and when to use it

Makes Eval Studio draw each trace the way the user saw it when no built-in view fits. Chooses between a panel layout in the product setup and a custom view file in pmstack/renderers/, writes it, and confirms it renders in the studio. Use when traces look like raw fields in Review traces, or when the product's output is not a chat, text message, phone call, email, document, answer with sources, agent steps, code review, form fields, or ranked list.

Original author description

Makes Eval Studio draw each trace the way the user saw it when no built-in view fits. Chooses between a panel layout in the product setup and a custom view file in pmstack/renderers/, writes it, and confirms it renders in the studio. Use when traces look like raw fields in Review traces, or when the product's output is not a chat, text message, phone call, email, document, answer with sources, agent steps, code review, form fields, or ranked list.

How it works

  1. Find the pmstack tool
  2. Guardrails
  3. Phase 1: Read the traces
  4. Phase 2: Choose the smallest thing that works
  5. Phase 3a: Write a panel layout
  6. Phase 3b: Write a custom view file
  7. Phase 4: Confirm it renders
  8. Report to the user
Original SKILL.md headings · 144 lines, 1,364 words
SKILL.md preview
---
name: pmstack-custom-view
description: Makes Eval Studio draw each trace the way the user saw it when no built-in view fits. Chooses between a panel layout in the product setup and a custom view file in pmstack/renderers/, writes it, and confirms it renders in the studio. Use when traces look like raw fields in Review traces, or when the product's output is not a chat, text message, phone call, email, document, answer with sources, agent steps, code review, form fields, or ranked list.
---

# Build a custom view of a trace

A reviewer can only judge what they can see. The view shows each trace the way the customer saw it, so the reviewer notices what the customer noticed: a raw `**` in a text message, a wrong price on a product card, a slide with overflowing text.

Use the project's user word (`experience.userLabel`, default "customer") wherever this skill says customer.

## Find the pmstack tool

`<skill-dir>` is this skill's base directory: the folder holding this SKILL.md, which your agent receives when it loads the skill. Run:

```sh
PMSTACK=""
for p in "<skill-dir>/../../../.pmstack/bin/pmstack.mjs" "<skill-dir>/../../bin/pmstack.mjs" "$HOME/.pmstack/bin/pmstack.mjs"; do
  [ -f "$p" ] && PMSTACK="$p" && break
done
```

It needs Node 20 or newer. If your shell forgets variables between commands, use the found path literally. If no path is found, send the user to https://ryanalberts.github.io/pmstack/studio/: its Set up tab offers every built-in view and "Build your own view" (the panel layout). Custom view files need the local studio. Never install npm packages.

## Guardrails

- While the studio runs (`pmstack/.studio.json` names a live process), change the product setup in the studio's Set up tab, not in `project.json`. Check with:

```sh
node -e 'try{process.kill(JSON.parse(require("fs").readFileSync("pmstack/.studio.json","utf8")).pid,0);console.log("studio running")}catch{console.log("studio not running")}'
```

- When you edit `pmstack/project.json` with the studio stopped, add 1 to `revision`, update `updatedAt`, and run `node "$PMSTACK" validate pmstack/project.json` afterwards.
- Claim a view works only after you have seen it render.

## Phase 1: Read the traces

Read 5 to 10 traces that differ: short and long, each channel or product line, one with an error. For each, write down:

- What the customer actually saw, and in what form (a text bubble, a product card, a slide, a calendar invite, a filled form).
- Which fields change from trace to trace and which stay the same.
- Which details a reviewer would want to filter on (channel, plan, language, product line).
- Which internal steps explain the output (search results, tool calls and their results).

Phase 1 is done when you can describe, in one sentence per trace, what the customer saw.

## Phase 2: Choose the smallest thing that works

| Situation | Use |
|---|---|
| A built-in view matches: chat (text, web chat, phone calls), email, document, answer with sources, agent steps, code review, form fields, ranked list | Set `experience.renderer` to it and stop |
| Different traces need different built-in views (calls and texts, for example) | `experience.rendererBy`: `{ "key": "channel", "map": { "email": "email" } }` |
| The trace is a few fields, each fine as text, formatted text, chat, cards, a table, details, or structured data | A panel layout (Phase 3a) |
| The customer saw something panels cannot draw: a styled card, a slide, an image with overlays, two items side by side | A custom view file (Phase 3b) |

Phase 2 is done when you have picked one row and can say why the row above it falls short.

## Phase 3a: Write a panel layout

Set `experience.renderer` to `"layout"` and list the panels in `experience.layout`, in reading order:

```json
"layout": [
  { "label": "Shopper's request", "path": "input", "as": "text" },
  { "label": "What the shopper saw", "path": "output.items", "as": "cards" },
  { "label": "Search results", "path": "steps[0].output", "as": "table" }
]
```

`path` points into the raw trace (dots and `[index]`). `as` is one of `text`, `markdown`, `chat`, `cards`, `table`, `details`, `json`. Each panel becomes a pickable step `panel:<i>`, so the reviewer can mark the first panel that went wrong. The studio's "Build your own view" card edits the same list with a live preview.

## Phase 3b: Write a custom view file

Write `pmstack/renderers/<id>.mjs`. The id matches `^[a-z0-9][a-z0-9-]{0,40}$`, such as `slide-card`. Then set `experience.renderer` to `"custom:<id>"`, or name it in a `rendererBy` map. Custom views load only in the local studio.

Read these before writing, so you match the real contract:

- `$(dirname "$PMSTACK")/../docs/studio/renderers/common.mjs`: the shared pieces and their props.
- One built-in view close to your case in the same folder, such as `list.mjs` or `chat.mjs`.
- `examples/quickstart/pmstack/renderers/sms-card.mjs` in the pmstack repository, when available: a complete custom view.

The contract:

- Export the component as the module's default export.
- Import only from `pmstack/ui` (`html`, hooks, small components), `pmstack/renderers/common`, and `preact/hooks`. No other imports, no network requests, no remote images.
- Props: `{ trace, experience, showHidden, pickedStepId, onPickStep, highlights, stepBadges, retrieval, onRetrieval, compact }`. Every callback may be missing; with no `onPickStep`, draw no pick button.
- `stepBadges` is `{ [stepId]: [{ tone, text }] }`, such as a policy check's "Breaks policy: Ask before acting". Draw each step's badges next to it with `StepBadges` and `badgesFor` from `pmstack/renderers/common`: `<${StepBadges} badges=${badgesFor(stepBadges, step.id)} />`.
- `trace` is the normalized trace: `id`, `title`, `metadata` (flat keys like `channel`), `context` (`[{ label, value }]`), `input`, `steps` (`id`, `kind`, `role`, `name`, `text`, `data`, `status`, `stage`, `callId`, `customerVisible`, `isOutput`), and `output`. The studio draws `trace.result` itself; leave it out.
- Every element that shows a step carries `data-step-id` with that step's `id`, and shows its stage tag when `step.stage` is set.
- A step the reviewer can blame offers the shared pick button, which calls `onPickStep(step.id, step.stage)`; the picked step (`pickedStepId`) shows as picked.
- When `showHidden` is false, internal steps (system, tool calls and results, search, model steps) collapse into the shared "steps behind the scenes" expander in place. They stay one click away.
- Write markup with htm: components as `<${Comp} ...>` closed with `<//>`, `class` (not `className`), `onInput` for text fields, kebab-case SVG attributes such as `stroke-width`. Render text as text; formatted text goes through the shared `Markdown` component. Never set inner HTML.
- Style with inline `style` attributes that use the studio's color variables (`var(--surface)`, `var(--surface-2)`, `var(--ink)`, `var(--ink-2)`, `var(--line)`), so light and dark themes both work.

A minimal starting shape, before adding the shared pieces:

```js
import { html } from 'pmstack/ui';

// Draws the slide the customer saw. Every step element carries data-step-id.
export default function SlideView({ trace, pickedStepId }) {
  const out = trace.steps.find((s) => s.isOutput);
  return html`
    <article style="background: var(--surface); color: var(--ink)">
      <h4>${trace.title}</h4>
      ${out && html`
        <section data-step-id=${out.id} aria-current=${out.id === pickedStepId ? 'true' : null}>
          ${out.text}
        </section>`}
    </article>`;
}
```

Design rules:

- Show the output exactly as the customer saw it. If a text message showed `**Friday**` literally, the view shows the asterisks.
- Put details worth filtering on at the top as chips, and add their keys to `experience.filters`.
- Keep every role at full strength. System prompts and tool results often hold the bug; collapse them, never fade them.
- Draw each tool call together with its result (matching `callId`), so cause and effect sit side by side.
- Status never relies on color alone: pair color with a word or icon.

Before starting the studio, check the syntax: `node --check pmstack/renderers/<id>.mjs`.

## Phase 4: Confirm it renders

1. Run `node "$PMSTACK" validate pmstack/project.json`.
2. Start the studio in the background and read the one line it prints, `Eval Studio: http://127.0.0.1:<port>/`:

```sh
node "$PMSTACK" studio <folder> --port 0
```

3. For a custom view file, confirm the server finds it: `curl -s -o /dev/null -w "%{http_code}\n" "<url>custom/renderers/<id>.mjs"` prints `200`.
4. Open `<url>#/review/<trace-id>` for 3 of the traces from Phase 1 (encode the id with `encodeURIComponent`). With a browser tool: take a screenshot of each, read the console, and count `[data-step-id]` elements. Toggle "Show behind-the-scenes steps" (H) and click a step's "First thing that went wrong" button once.
5. Without a browser tool, give the user the URLs and ask them to look. Say plainly that you have not seen it render.
6. Stop the studio you started unless the user wants to keep reviewing.

Phase 4 is done when 3 traces render in the new view with a clean console, a `data-step-id` on every step, and a working pick button, and the "Custom view <id> could not load" notice never appears.

## Report to the user

```
View: <built-in name | layout with n panels | custom:<id>>
Why: <one line on what the customer saw that the built-in views missed>
Checked on: <3 trace ids>, <screenshots taken | not seen, user to confirm>
Filters added: <keys>
```

Versions

The database has no other skills named pmstack-custom-view.

Database snapshot: 13.11.2026 · package version 75298a0f5d46 (SHA-256 digest of the entire package)

Downloads in the last 30 days: 0 · ranking

Report a problem with this skill: harmful content, incorrect descriptions or an author’s removal request.

Similar skills

  • 100pmstack-make-traces
    Makes realistic test traces for an AI product that has few or no real ones: writes test requests, runs them through the product, and saves the results as traces ready to review in Eval Studio. Starts from three ways the product is likely to fail, checks 20 combinations with the…
  • 100pmstack-find-failures
    Finds how an AI product fails, with a person reviewing real traces in Eval Studio. Finds or creates a trace file, sets up a pmstack project (how traces look, the product's stages, filters), starts the local studio, watches reviews as they come in, and suggests likely problems,…
  • 100opik-annotate
    Set up human review in Opik — create an annotation queue for a project's traces or threads and give it a custom annotator view, an HTML page that shows annotators each item the way they need to judge it (the email beside the reply, the conversation as chat bubbles) instead of…
  • 100beacon-lens-create
    Create, revise, debug or validate a Beacon lens, a single HTML file that renders one agent trace as a purpose-built view (a per-file review, a cost breakdown, a timeline of risky commands, a map of tool use) in a sandboxed tab of the local Beacon dashboard, fed once through…
  • 100beacon-lens-create
    Create, revise, debug or validate a Beacon lens, a single HTML file that renders one agent trace as a purpose-built view (a per-file review, a cost breakdown, a timeline of risky commands, a map of tool use) in a sandboxed tab of the local Beacon dashboard, fed once through…

Feedback and reports

Your message goes to Bartosz Sokoliński. An email address is needed only for a reply. See the privacy policy.