Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ Each lives at `skills/<name>/` with its own `SKILL.md`, `scripts/`, and `referen
| `dynamodb-modeling` | Design a DynamoDB table or review one before it ships: \"what should my partition key be\", \"do I need a GSI here\", \"is this single-table design right\", \"review my access patterns\", or any new table/entity in a Dynamo-backed service. Access-pattern-first modeling, key strategies, index choice, and the anti-patterns that show up in review. |
| `grill-for-planning` | Stress-test a vague plan, decision, or idea before it's written down — \"grill me on this\", \"poke holes in this idea\", \"help me think this through\". Round-based interview that maps the idea into a decision tree and works it to a shared understanding. For prepping a specific artifact (RFC/PR/promo packet) against a review panel, use skill-tree:grill-for-quality instead. |
| `grill-for-quality` | Prep a specific artifact (design doc, PR/diff, promo packet, slides, or an entire codebase) for a real review panel, interview, or presentation — \"grill me on this RFC\", \"quiz me for promo\". Adaptive adversarial interview that pushes on real weak points. For stress-testing a vague plan or decision that isn't written down yet, use skill-tree:grill-for-planning instead. |
| `grill-for-visualization` | Turn an idea into a polished coded video (product showcase or system/concept explainer) — \"make an animation of how X works\", \"visualize this for a demo\", \"grill me for a visualization\". Round-based interview about what to show, a storyboard the user approves, then a React project that renders an MP4, with the source kept editable. For stress-testing a plan with no video at the end, use skill-tree:grill-for-planning instead. |
| `handoff` | A session needs to end or continue elsewhere — \"write a handoff\", \"I'm running low on context\", \"continue where we left off\". Writes and resumes a handoff that survives compaction. |
| `implement` | Implement a ticket or spec — \"build this\", \"implement the next ticket\", \"start working\". TDD by default at pre-agreed seams, typechecks regularly, and presents verified work for review. Human-in-the-loop by default; pass 'autonomous' to work the full frontier with guardrails. |
| `node-style` | Read before writing Node, TypeScript, or JavaScript code. Covers type safety, ESLint, error handling, testing (Jest/Vitest), and package management. |
Expand Down
4 changes: 2 additions & 2 deletions evals/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ does with the playbook.

```bash
just eval # pick a suite (fzf), or lists them off a TTY
just eval ui-designer # 2 cases, ~2.5 min, ~$0.55–0.70
just eval ui-designer # 3 cases, ~3 min, ~$0.75–0.90
just eval debug-ci # 3 cases, ~1.5 min, ~$0.60
just eval repo-audit # 5 cases
just eval handoff # 6 fixtures, skill arm only
Expand All @@ -20,7 +20,7 @@ just eval ui-designer --ablation with-without # also run without the plugin, re
| Suite | Runner | What it checks |
|---|---|---|
| `debug-ci` | `claude plugin eval` | diagnose from the CI log, fix, verify locally, no git writes |
| `ui-designer` | `claude plugin eval` | the skill's design rules, as greppable checks on a built page and a review |
| `ui-designer` | `claude plugin eval` | the skill's design rules, as greppable checks on a built page, a review of a generic landing page, and a review of a cluttered dashboard table |
| `repo-audit` | `claude plugin eval` | runs the checker, read-only, report format, catches the seeded gaps |
| `two-axis-review` | `claude plugin eval` | both axes run as sub-agents, each seeded issue lands on its axis, read-only |
| `verify` | `claude plugin eval` | runs a check that could fail before answering: dynamic `getattr` use, a fix that misses its own case, a suite failing outside the changed module; plus a negative-trigger case |
Expand Down
69 changes: 69 additions & 0 deletions evals/ui-designer/03-dashboard-review/case.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
schema_version: "1.0"
name: ui-designer/03-dashboard-review
description: >-
Review-only: a dashboard table seeded with one defect per lesson 9-12
idea. Font and token values are ruled out of scope in the prompt so lessons
1-3 don't crowd the review. One grader per defect, since a single
multi-part rubric over a long review is flaky (see evals/README.md).
tags: [ui-designer]
context:
scaffold_script: scaffold.sh
execution:
prompt: >-
The Employees screen of our admin dashboard feels cluttered and hard to
scan. Review the design and tell me what you'd change. Don't edit
anything yet. The font and the color token values come from our design
system, so leave those alone.
max_turns: 10
timeout_seconds: 180
allowed_tools: [Read, Glob, Grep, Edit, Write, Skill]
runs: 1
graders:
- type: tool_used
name: skill-fired
tool: Skill
input_match: ui-designer
- type: file_exists
name: no-new-files
path: '**'
exists: false
- type: regex
name: index-html-unchanged
target: { source: file, path: index.html }
pattern: 'Status: All[\s\S]*<button class="icon-btn">⟳</button>[\s\S]*<td>Inactive</td><td>0</td>[\s\S]*<button>Copy ID</button><button>Remove</button>'
- type: regex
name: style-css-unchanged
target: { source: file, path: style.css }
pattern: '\.chip \{\s*background: var\(--accent\);[\s\S]*text-align: left;'
- type: llm
name: enum-columns-as-chips
criteria: >-
PASS if the final message says the Department or Status values should
be chips, badges, or pills (or otherwise visually distinct) instead of
plain text, or that Inactive / On leave rows should be dimmed or
visually set apart. Otherwise FAIL.
- type: llm
name: right-align-numbers
criteria: >-
PASS if the final message says the numeric "Hours this week" column
should be right-aligned (or aligned by decimal / place value, or set in
tabular figures). Otherwise FAIL.
- type: llm
name: default-chips-not-accented
criteria: >-
PASS if the final message says the filter chips (Department: All,
Status: All, Location: All) shouldn't all use the accent color while in
their default "All" state, e.g. that accent should mark only an active
or non-default filter. Otherwise FAIL.
- type: llm
name: hide-secondary-row-actions
criteria: >-
PASS if the final message says the per-row Share / Copy ID / Remove
buttons shouldn't all be permanently visible on every row, e.g. reveal
them on hover or focus, or move them into a menu or popover. Otherwise
FAIL.
- type: llm
name: label-icon-buttons
criteria: >-
PASS if the final message says the toolbar's icon-only buttons
(⟳ ⤓ ⚙) need accessible names (aria-label) or tooltips. Otherwise FAIL.
144 changes: 144 additions & 0 deletions evals/ui-designer/03-dashboard-review/scaffold.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
#!/usr/bin/env bash
set -euo pipefail

cat >index.html <<'EOF'
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Employees · Crewbase</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<main>
<header class="toolbar">
<h1>Employees</h1>
<div class="filters">
<button class="chip">Department: All</button>
<button class="chip">Status: All</button>
<button class="chip">Location: All</button>
</div>
<div class="tools">
<button class="icon-btn">⟳</button>
<button class="icon-btn">⤓</button>
<button class="icon-btn">⚙</button>
</div>
</header>
<table>
<thead>
<tr><th>Name</th><th>Department</th><th>Status</th><th>Hours this week</th><th>Actions</th></tr>
</thead>
<tbody>
<tr>
<td>Ana Okafor</td><td>Engineering</td><td>Active</td><td>38.5</td>
<td class="actions"><button>Share</button><button>Copy ID</button><button>Remove</button></td>
</tr>
<tr>
<td>Ben Halvorsen</td><td>Support</td><td>Inactive</td><td>0</td>
<td class="actions"><button>Share</button><button>Copy ID</button><button>Remove</button></td>
</tr>
<tr>
<td>Chloé Marchetti</td><td>Engineering</td><td>On leave</td><td>4</td>
<td class="actions"><button>Share</button><button>Copy ID</button><button>Remove</button></td>
</tr>
<tr>
<td>Dev Raman</td><td>Sales</td><td>Active</td><td>112.25</td>
<td class="actions"><button>Share</button><button>Copy ID</button><button>Remove</button></td>
</tr>
<tr>
<td>Eun-ji Park</td><td>Support</td><td>Active</td><td>40</td>
<td class="actions"><button>Share</button><button>Copy ID</button><button>Remove</button></td>
</tr>
</tbody>
</table>
</main>
</body>
</html>
EOF

cat >style.css <<'EOF'
:root {
--font-body: "Inter", sans-serif;
--surface: #f7f6f3;
--surface-raised: #fdfcfa;
--text: #1d1c1a;
--text-muted: #6b6862;
--border: #e2dfd8;
--accent: #2f5d50;
--accent-contrast: #f7f6f3;
--space-1: 4px;
--space-2: 8px;
--space-3: 12px;
--space-4: 16px;
--space-6: 24px;
--space-8: 32px;
}
body {
font-family: var(--font-body);
color: var(--text);
background: var(--surface);
margin: 0;
}
main {
max-width: 1100px;
margin: 0 auto;
padding: var(--space-8) var(--space-6);
}
:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
.toolbar {
display: flex;
align-items: center;
gap: var(--space-4);
margin-bottom: var(--space-6);
}
.filters,
.tools {
display: flex;
gap: var(--space-2);
}
.tools {
margin-left: auto;
}
.chip {
background: var(--accent);
color: var(--accent-contrast);
border: 0;
border-radius: 999px;
padding: var(--space-1) var(--space-3);
}
.icon-btn {
background: none;
border: 1px solid var(--border);
border-radius: 6px;
padding: var(--space-2);
}
table {
width: 100%;
border-collapse: collapse;
background: var(--surface-raised);
}
th,
td {
text-align: left;
padding: var(--space-3) var(--space-4);
border-bottom: 1px solid var(--border);
}
th {
color: var(--text-muted);
font-weight: 500;
}
.actions {
display: flex;
gap: var(--space-2);
}
.actions button {
background: none;
border: 1px solid var(--border);
border-radius: 6px;
padding: var(--space-1) var(--space-3);
}
EOF
10 changes: 10 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,19 @@ default:
@echo " just output-style <name> Create an output style in output-styles/<name>.md"
@echo " just install Symlink skills, CLIs, and output styles into ~/"
@echo " just eval <skill> [flags] Run the evals in evals/<skill>/"
@echo " just qa Lint and test, the same checks CI runs"
@echo ""
@echo "skill and output-style open the new file in VS Code or \$EDITOR."

qa: lint test

# pytest runs in `test`; commitizen-early has no commit message to check.
lint:
SKIP=pytest,commitizen-early prek run --all-files --show-diff-on-failure

test:
uv run --with pytest --with pytest-xdist pytest scripts/ skills/ -q

skill name:
@./scripts/new-skill.sh {{name}}

Expand Down
3 changes: 3 additions & 0 deletions skills/.length-baseline
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@ dynamodb-cost-audit: 182
handoff: 230
repo-audit: 177
site-launch: 177
# No CLI, but the same shape: twelve numbered lessons, each ending in its
# own Check. Moving lessons into references/ splits the list.
ui-designer: 195
111 changes: 111 additions & 0 deletions skills/grill-for-visualization/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
---
name: grill-for-visualization
description: "Turn an idea into a polished coded video (product showcase or system/concept explainer) — \"make an animation of how X works\", \"visualize this for a demo\", \"grill me for a visualization\". Round-based interview about what to show, a storyboard the user approves, then a React project that renders an MP4, with the source kept editable. For stress-testing a plan with no video at the end, use skill-tree:grill-for-planning instead."
user-invocable: true
disable-model-invocation: true
allowed-tools: Read, Write, Edit, Grep, Glob, Bash, WebFetch
---

# Grill For Visualization

Interview the user until you know exactly what the video must say, get a storyboard approved,
then build it. The output is a self-contained project directory: a rendered MP4 plus the React
source that produced it, runnable with `npm install` and two scripts.

Read [references/BRIEF.md](references/BRIEF.md) before the first round. It is the creative
standard for everything below: composition, motion, typography, and the review checklist.

## 1. Grill

Use the round format and frontier rule from
[grill-for-planning](../grill-for-planning/SKILL.md): ask every question whose prerequisites
are settled in one numbered round, give a recommended answer for each, wait, recompute. Look
facts up yourself (repo, docs, brand assets on disk); put decisions to the user.

The design tree, roughly in dependency order:

- **Purpose.** What is being visualized, and is it a product showcase or an explainer of how
something works? Who watches it, and where (meeting screen, phone, embedded in a doc)? What
is the one thing they should understand afterwards?
- **Stack.** Is this for personal use or for work at a for-profit company of more than three
people? This picks the stack in step 3, so ask it in the first round.
- **Truth.** The actual rules, thresholds, steps, and numbers. Limitations and caveats that
must be shown honestly. Anything that must not appear (confidential details, competitor
names, unreleased features).
- **Form.** Duration, aspect ratio, available assets (logo, screenshots, brand colors, fonts),
mood or reference pieces, tone of the copy, the closing line.

Keep going for as many rounds as the tree needs. Stop when the frontier is empty, not when
the answers start to feel sufficient.

Never invent functionality, customer claims, or metrics to fill a gap: ask. If the user says
to just go, stop asking, make the remaining calls yourself, and list every assumption beside
the storyboard so each one can be corrected.

## 2. Storyboard

Present one table, one row per scene: what the viewer sees, what they should understand, the
on-screen copy, approximate duration, and how it hands off to the next scene. Under it, list
assumptions and anything illustrative rather than factual.

Do not create files until the user approves the storyboard. Changes loop back here.

## 3. Scaffold

Pick the stack from the answer in step 1 and read its reference:

- Personal use, or the user confirms they hold a Remotion license:
[references/REMOTION.md](references/REMOTION.md).
- Work, or any doubt: [references/FREE.md](references/FREE.md). Same authoring API, no
license requirement.

Scenes import from `./runtime` in both stacks, so everything in the brief applies to either.

Create the project in `./<slug>/` (or the current directory if it is empty), where `<slug>` is
a short kebab-case name for the piece:

```bash
T="${CLAUDE_PLUGIN_ROOT:-${SKILL_TREE_DIR:-$HOME/projects/skill-tree}}/skills/grill-for-visualization/templates"
mkdir -p <slug> && cp -r "$T/shared/." "$T/<free|remotion>/." <slug>/
```

Then set `name` and the output filename in `package.json` to the slug, and install with the
commands in the stack reference. Dependencies are installed with `--save-exact` at their
current versions; the templates carry none.

## 4. Build

1. **Logic first, test first.** Every number or state shown on screen comes from a pure
function in `src/logic/` with a parametrized test beside it. A hand-typed figure in a
scene drifts from the facts the moment the user edits one of them.
2. **Content.** Copy, colors, and timing go in `content.ts` under `src/`; add each scene to
`timing` and `SCENE_ORDER`, and to the component map in `Video.tsx`. Total duration
derives from these.
3. **Sequence, then polish.** Get every scene on screen in order with final copy before
refining any one of them. Shared pieces go in `src/components/`.
4. Run `npm test` and `npm run typecheck`.

## 5. Review

Render one still for every beat of every scene (each point where something has just appeared
or settled), and open each image. Check them against the checklist at the end of the brief:
clipping, overlap, text size, one focal point per frame, an ending that holds. Fix and render
again until a full pass is clean. Then render the MP4.

Looking at the frames is the step that makes the result good. Passing tests say nothing about
whether a label sits on top of a vehicle.

## 6. Deliver

Write `README.md` in the project:

- Length, resolution, frame rate, and the commands (`npm install`, `npm run dev`,
`npm run render`, `npm test`).
- The storyboard as built.
- A "change X in file Y" table: copy, colors, facts and thresholds, scene timing, assets,
aspect ratio.
- Assumptions and anything illustrative.
- For the Remotion stack, the license note from its reference.

Tell the user where the MP4 is, what you assumed, and anything in the storyboard that changed
during the build.
Loading
Loading