use-agentz 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +308 -0
- package/dist/authoring/define.js +132 -0
- package/dist/cli.js +26581 -0
- package/dist/config/define.js +36 -0
- package/dist/ui/web/index.html +16 -0
- package/dist/ui/web/logo.png +0 -0
- package/dist/ui/web/main.tsx +2406 -0
- package/dist/ui/web/styles.css +2338 -0
- package/package.json +54 -0
- package/registry/r/agent.analyst.json +44 -0
- package/registry/r/agent.designer.json +34 -0
- package/registry/r/agent.developer.json +31 -0
- package/registry/r/agent.expert-orchestrator.json +36 -0
- package/registry/r/agent.expert.json +33 -0
- package/registry/r/agent.orchestrator.json +39 -0
- package/registry/r/agent.quick.json +28 -0
- package/registry/r/agent.reviewer-anthropic.json +34 -0
- package/registry/r/agent.reviewer-gpt.json +34 -0
- package/registry/r/agent.scout.json +34 -0
- package/registry/r/command.caveman.json +20 -0
- package/registry/r/command.grill-me.json +20 -0
- package/registry/r/group.cli-bun.json +13 -0
- package/registry/r/group.cli-go.json +13 -0
- package/registry/r/group.database-design.json +12 -0
- package/registry/r/group.design.json +14 -0
- package/registry/r/group.documents.json +13 -0
- package/registry/r/group.engineering-process.json +18 -0
- package/registry/r/group.go.json +21 -0
- package/registry/r/group.python.json +10 -0
- package/registry/r/group.react.json +11 -0
- package/registry/r/group.typescript.json +10 -0
- package/registry/r/lsp.proto.json +41 -0
- package/registry/r/mcp.context7.json +13 -0
- package/registry/r/mcp.playwright.json +50 -0
- package/registry/r/pack.basic.json +78 -0
- package/registry/r/pack.gpt-5-6.json +78 -0
- package/registry/r/pack.optimized.json +78 -0
- package/registry/r/pack.opus-fable.json +78 -0
- package/registry/r/plugin.caveman-compress.json +20 -0
- package/registry/r/preset.caveman-only.json +13 -0
- package/registry/r/preset.cost-aware-trio.json +41 -0
- package/registry/r/preset.cross-model-review.json +34 -0
- package/registry/r/preset.design.json +39 -0
- package/registry/r/preset.fable-pack.json +41 -0
- package/registry/r/preset.full.json +67 -0
- package/registry/r/rule.always-cross-review.json +25 -0
- package/registry/r/rule.always-design.json +25 -0
- package/registry/r/rule.always-qa.json +25 -0
- package/registry/r/rule.always-test.json +25 -0
- package/registry/r/rule.caveman-ultra.json +23 -0
- package/registry/r/rule.never-cross-review.json +25 -0
- package/registry/r/rule.never-design.json +25 -0
- package/registry/r/rule.never-qa.json +25 -0
- package/registry/r/rule.never-test.json +25 -0
- package/registry/r/rule.routing.json +26 -0
- package/registry/r/rule.use-question-tool.json +20 -0
- package/registry/r/skill.bun-cli.json +20 -0
- package/registry/r/skill.bun-tui.json +20 -0
- package/registry/r/skill.caveman-compress.json +17 -0
- package/registry/r/skill.caveman.json +20 -0
- package/registry/r/skill.cli-design.json +15 -0
- package/registry/r/skill.code-review.json +18 -0
- package/registry/r/skill.cost-aware-orchestration.json +14 -0
- package/registry/r/skill.cross-model-review.json +14 -0
- package/registry/r/skill.db-schema-design.json +15 -0
- package/registry/r/skill.design-system.json +19 -0
- package/registry/r/skill.design-taste.json +116 -0
- package/registry/r/skill.diagnosing-bugs.json +23 -0
- package/registry/r/skill.diagrams.json +21 -0
- package/registry/r/skill.docx-create.json +20 -0
- package/registry/r/skill.domain-modeling.json +18 -0
- package/registry/r/skill.frontend-qa.json +19 -0
- package/registry/r/skill.go-architecture.json +21 -0
- package/registry/r/skill.go-ci.json +21 -0
- package/registry/r/skill.go-cli.json +20 -0
- package/registry/r/skill.go-data-structures.json +21 -0
- package/registry/r/skill.go-dependencies.json +21 -0
- package/registry/r/skill.go-dev.json +20 -0
- package/registry/r/skill.go-documentation.json +21 -0
- package/registry/r/skill.go-ecosystem.json +21 -0
- package/registry/r/skill.go-qa.json +21 -0
- package/registry/r/skill.go-quality.json +21 -0
- package/registry/r/skill.go-refactoring.json +21 -0
- package/registry/r/skill.go-tooling.json +21 -0
- package/registry/r/skill.go-tui.json +20 -0
- package/registry/r/skill.go-types.json +21 -0
- package/registry/r/skill.grilling.json +18 -0
- package/registry/r/skill.improve-architecture.json +18 -0
- package/registry/r/skill.pdf-create.json +23 -0
- package/registry/r/skill.pptx-create.json +23 -0
- package/registry/r/skill.product-ui.json +22 -0
- package/registry/r/skill.python-dev.json +20 -0
- package/registry/r/skill.react-dev.json +20 -0
- package/registry/r/skill.resolving-merge-conflicts.json +18 -0
- package/registry/r/skill.scratchpad.json +17 -0
- package/registry/r/skill.skill-authoring.json +17 -0
- package/registry/r/skill.software-design.json +28 -0
- package/registry/r/skill.sql-migrations.json +15 -0
- package/registry/r/skill.tdd.json +28 -0
- package/registry/r/skill.typescript-dev.json +20 -0
- package/registry/r/skill.visual-assets.json +17 -0
- package/registry/r/skill.wayfinder.json +18 -0
- package/registry/r/skill.xlsx-create.json +20 -0
- package/registry/r/tool.a11y-quick.json +24 -0
- package/registry/r/tool.contrast-check.json +24 -0
- package/registry/r/tool.design-lint.json +24 -0
- package/registry/r/tool.design-search.json +23 -0
- package/registry/r/tool.pdf-create.json +23 -0
- package/registry/r/tool.pptx-create.json +23 -0
- package/registry/r/tool.scratchpad.json +68 -0
- package/registry/r/tool.token-validate.json +24 -0
- package/registry/registry.json +676 -0
- package/schema/agentz.schema.json +330 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"name": "pdf-create",
|
|
4
|
+
"type": "skill",
|
|
5
|
+
"title": "PDF creation",
|
|
6
|
+
"description": "Creating and editing PDF files with pdf-lib on Bun: reports, letters, multi-page documents, text layout, merging/splitting, watermarks, custom fonts. Use whenever asked to produce, generate, merge, split, or edit a .pdf file.",
|
|
7
|
+
"dependencies": [
|
|
8
|
+
"tool:pdf-create"
|
|
9
|
+
],
|
|
10
|
+
"files": [
|
|
11
|
+
{
|
|
12
|
+
"path": "SKILL.md",
|
|
13
|
+
"content": "---\nname: pdf-create\nlabel: \"PDF creation\"\ndependencies: [bun]\ntool: pdf-create\nsource: https://github.com/anthropics/skills/tree/main/skills/pdf\ndescription: >\n Creating and editing PDF files with pdf-lib on Bun: reports, letters,\n multi-page documents, text layout, merging/splitting, watermarks, custom\n fonts. Use whenever asked to produce, generate, merge, split, or edit a\n .pdf file.\n---\n\n# PDF creation (pdf-lib)\n\nGenerate PDFs from code — reproducible scripts, no GUI tools.\n\n## Tool choice\n\n- **opencode**: the `pdf-create` tool turns markdown-lite text into a paginated\n PDF in one call — use it for plain text documents (reports, letters, notes).\n- **Everything else** (precise layout, tables, images, merging, forms): write a\n one-off script with [`pdf-lib`](https://pdf-lib.js.org) and run it with\n `bun --install=fallback script.ts` — Bun auto-resolves the import, no\n package.json needed.\n\n## pdf-lib basics\n\n```ts\nimport { PDFDocument, StandardFonts, rgb, PageSizes } from \"pdf-lib\"\n\nconst doc = await PDFDocument.create()\nconst font = await doc.embedFont(StandardFonts.Helvetica)\nconst bold = await doc.embedFont(StandardFonts.HelveticaBold)\nconst page = doc.addPage(PageSizes.A4) // 595.28 x 841.89 pt\npage.drawText(\"Quarterly Report\", { x: 72, y: page.getHeight() - 72, size: 24, font: bold })\nawait Bun.write(\"report.pdf\", await doc.save())\n```\n\n- Coordinates are **bottom-left origin**: track a cursor `y` starting at\n `height - margin` and subtract `size * 1.4` per line.\n- No automatic text wrapping — wrap manually with\n `font.widthOfTextAtSize(line, size)` against the content width, and add a\n fresh page when `y < margin`.\n- 72 pt = 1 inch. Use ≥ 54 pt margins; body 10–12 pt, headings 16–24 pt.\n\n## Fonts & unicode\n\nStandard fonts (Helvetica & co) encode **WinAnsi/Latin-1 only** — non-Latin\ntext or fancy unicode (smart quotes, em dashes work; CJK, Cyrillic don't)\n**throws at draw time**. For other scripts embed a TTF:\n\n```ts\nimport fontkit from \"@pdf-lib/fontkit\"\ndoc.registerFontkit(fontkit)\nconst custom = await doc.embedFont(await Bun.file(\"NotoSans.ttf\").arrayBuffer())\n```\n\n## Merge / split / stamp\n\n```ts\nconst merged = await PDFDocument.create()\nfor (const file of [\"a.pdf\", \"b.pdf\"]) {\n const src = await PDFDocument.load(await Bun.file(file).arrayBuffer())\n const pages = await merged.copyPages(src, src.getPageIndices())\n pages.forEach((p) => merged.addPage(p))\n}\n```\n\nSplit: copy index ranges into separate docs. Watermark: `drawText` with\n`opacity: 0.3, rotate: degrees(45)` on every page of a loaded doc.\n\n## Filling forms\n\n- Fillable forms: detect fields FIRST, extract each field's id, type\n (text/checkbox/radio/choice), page, and bounding box; render pages to images\n to map each field's purpose; build a values map; fill, then re-render and\n visually inspect placement.\n- Static (non-fillable) forms: work structure-first — locate label and entry\n bounding boxes, place text at those coordinates, and validate every bounding\n box (no intersections, entry box big enough for the font) before drawing.\n- Always render and eyeball the filled output; coordinate math is easy to get\n wrong.\n\n## Repair, optimize, large docs\n\n- `qpdf` (CLI) for repair, linearize/optimize, encrypt/decrypt, and\n split/merge: e.g. `qpdf --split-pages input.pdf out_%d.pdf`,\n `qpdf --decrypt in.pdf out.pdf`.\n- Large PDFs: stream/chunk page-by-page and split into ranges BEFORE processing\n rather than loading the whole document into memory.\n- A Python stack (pypdf/pdfplumber/pdfium) covers the same operations if the\n JS toolchain is unavailable.\n\n## QA (always)\n\n- Reload the output with `PDFDocument.load()` and assert the page count.\n- If `pdftotext` is on PATH, extract and grep for required content.\n- Never declare success without checking the file exists and is non-empty.\n",
|
|
14
|
+
"kind": "skill-md"
|
|
15
|
+
}
|
|
16
|
+
],
|
|
17
|
+
"meta": {
|
|
18
|
+
"systemDependencies": [
|
|
19
|
+
"bun"
|
|
20
|
+
],
|
|
21
|
+
"source": "https://github.com/anthropics/skills/tree/main/skills/pdf"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"name": "pptx-create",
|
|
4
|
+
"type": "skill",
|
|
5
|
+
"title": "PPTX creation",
|
|
6
|
+
"description": "Creating PowerPoint decks with pptxgenjs on Bun: slide layouts, master slides, text/tables/charts/images, speaker notes, design rules (palette, typography, spacing) and a visual QA loop. Use whenever asked to create a deck, slides, presentation, pitch deck, or a .pptx file.",
|
|
7
|
+
"dependencies": [
|
|
8
|
+
"tool:pptx-create"
|
|
9
|
+
],
|
|
10
|
+
"files": [
|
|
11
|
+
{
|
|
12
|
+
"path": "SKILL.md",
|
|
13
|
+
"content": "---\nname: pptx-create\nlabel: \"PPTX creation\"\ndependencies: [bun]\ntool: pptx-create\nsource: https://github.com/anthropics/skills/tree/main/skills/pptx\ndescription: >\n Creating PowerPoint decks with pptxgenjs on Bun: slide layouts, master\n slides, text/tables/charts/images, speaker notes, design rules (palette,\n typography, spacing) and a visual QA loop. Use whenever asked to create a\n deck, slides, presentation, pitch deck, or a .pptx file.\n---\n\n# PPTX creation (pptxgenjs)\n\nGenerate decks from code — reproducible scripts, no GUI tools.\n\nFor HTML decks or screenshot-ready slides (not native `.pptx`), use the visual-assets skill instead.\n\n## Tool choice\n\n- **opencode**: the `pptx-create` tool builds a clean title + bullet-slide deck\n in one call — use it for straightforward content decks.\n- **Everything else** (custom layouts, images, charts, tables, branding): write\n a script with [`pptxgenjs`](https://gitbrent.github.io/PptxGenJS/) and run it\n with `bun --install=fallback script.ts` — Bun auto-resolves the import.\n\n## pptxgenjs basics\n\n```ts\nimport Pptxgen from \"pptxgenjs\"\n\nconst pres = new Pptxgen()\npres.layout = \"LAYOUT_16x9\" // 10 x 5.625 in; positions are inches\nconst slide = pres.addSlide()\nslide.background = { color: \"1E2761\" }\nslide.addText(\"Q3 Results\", { x: 0.6, y: 2.2, w: 8.8, h: 1, fontSize: 40, bold: true, color: \"FFFFFF\" })\nslide.addNotes(\"Open with the revenue headline.\")\nawait pres.writeFile({ fileName: \"deck.pptx\" })\n```\n\n- Bullets: `slide.addText([{ text: \"Point\", options: { bullet: true } }], { x, y, w, h })`.\n- Tables: `slide.addTable(rows, { x, y, w, border, fill })`. Charts:\n `slide.addChart(pres.ChartType.bar, data, { x, y, w, h })`.\n- Consistent branding: `pres.defineSlideMaster({ title: \"MAIN\", background, objects })`\n then `pres.addSlide({ masterName: \"MAIN\" })`.\n\n## pptxgenjs gotchas (cause file corruption or silent bugs)\n\n- Colors are **6-digit hex WITHOUT `#`** (`\"FF0000\"`). A `#` prefix or 8-digit\n hex (opacity baked in) corrupts the file; set transparency via the `opacity`\n option instead.\n- Shadow `offset` must be non-negative — negative offsets corrupt the file. For\n an upward shadow use `angle: 270` with a positive offset.\n- Never share one option object across textboxes/shapes: pptxgenjs mutates it\n in-place (converts values to EMU), so the second call gets corrupted values.\n Build a fresh object per call (a `makeShadow()` factory).\n- Fresh `new Pptxgen()` instance per output file; do not reuse instances.\n- `charSpacing`, not `letterSpacing` (the latter is silently ignored).\n- Line breaks need `breakLine: true` on each run/array item.\n- Native bullets only (`bullet: true`); manual glyphs like `•` produce double\n bullets.\n- Template-edit path exists (unpack the `.pptx` XML, edit, repack) when working\n from an existing deck rather than generating from scratch.\n\n## Design rules (don't make boring slides)\n\n- **Palette**: pick topic-informed colors, never default blue. One dominant\n color (~60-70%), 1-2 supporting tones, one accent. Dark title/closing slides,\n light content slides — or commit to dark throughout.\n- **Typography**: title 36-44 pt bold, section headers 20-24 pt, body 14-16 pt,\n captions 10-12 pt. Left-align body text; center only titles.\n- **Spacing**: ≥ 0.5 in margins, 0.3-0.5 in between blocks — consistently.\n- **Every slide needs a visual element** (image, chart, icon shape, stat\n callout); vary layouts (two-column, grids, big-number callouts, timelines).\n- **Never** put accent lines under titles (AI-slide hallmark), repeat one\n layout everywhere, or leave placeholder text in the output.\n\n## QA (always)\n\nAssume the first render is wrong — hunt for bugs:\n\n- Reopen/verify the file exists and is non-empty; slide count matches plan.\n- Extract text (`markitdown` or equivalent) and scan for leftover placeholder\n text and truncated/overflowing content.\n- If LibreOffice is available, render and inspect:\n `soffice --headless --convert-to pdf deck.pptx && pdftoppm -jpeg -r 100 deck.pdf slide`\n then check images for overflow, overlap, low contrast, uneven spacing.\n- Fix → re-render → re-check; one fix often breaks another slide.\n",
|
|
14
|
+
"kind": "skill-md"
|
|
15
|
+
}
|
|
16
|
+
],
|
|
17
|
+
"meta": {
|
|
18
|
+
"systemDependencies": [
|
|
19
|
+
"bun"
|
|
20
|
+
],
|
|
21
|
+
"source": "https://github.com/anthropics/skills/tree/main/skills/pptx"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"name": "product-ui",
|
|
4
|
+
"type": "skill",
|
|
5
|
+
"title": "product-ui",
|
|
6
|
+
"description": "Operational shadcn-style app interfaces: data tables, CRUD forms, wizards, settings, dashboards, and other daily-use screens. Load design-taste for visual foundations; product-ui decides product-screen trade-offs, while design-taste leads marketing and portfolio work.",
|
|
7
|
+
"dependencies": [
|
|
8
|
+
"skill:design-taste"
|
|
9
|
+
],
|
|
10
|
+
"files": [
|
|
11
|
+
{
|
|
12
|
+
"path": "SKILL.md",
|
|
13
|
+
"content": "---\nname: product-ui\ndescription: >\n Operational shadcn-style app interfaces: data tables, CRUD forms, wizards,\n settings, dashboards, and other daily-use screens. Load design-taste for\n visual foundations; product-ui decides product-screen trade-offs, while\n design-taste leads marketing and portfolio work.\nrequires: [design-taste]\n---\n\n# Product UI\n\nProduct UI is judged in the 500th hour, not the first 5 seconds. Optimize for work done fast, zero confusion, calm on the 500th open. Always load `design-taste` alongside: it carries the shared aesthetic canon (typography, color, motion, dial system) this skill builds on. Marketing, landing, portfolio: `design-taste` leads. On product UIUX this skill wins every conflict, design-taste wins on visuals and asthetics.\n\nPrecedence: product screens: product-ui > design-system > design-taste. Marketing/visual: design-taste > design-system. Tools (design-lint etc.) are advisory heuristics; a skill rule beats a tool WARN, and a deliberate documented choice beats both.\n\n## Screen read (before any code)\n\nState one line first: screen kind, primary user task, usage frequency, data shape, sibling conventions. Consistency with sibling screens beats local perfection. Ambiguous brief: ask exactly ONE question, then proceed.\n\nDials: DESIGN_VARIANCE / MOTION_INTENSITY / VISUAL_DENSITY (1-10). Presets:\n\n| Screen | V | M | D |\n|---|---|---|---|\n| Table, daily use | 2 | 2 | 7 |\n| Table, occasional | 2 | 2 | 5 |\n| Detail page | 2 | 2 | 5 |\n| Form | 1 | 2 | 4 |\n| Wizard | 1 | 3 | 4 |\n| Dashboard | 3 | 3 | 6 |\n| Settings (boring is correct) | 1 | 1 | 4 |\n| Empty shell / new module | 2 | 2 | 4 |\n\nDensity maps to a spacing system. LOCK it per screen, never mix:\n\n- D 4-5: sections `py-6`/`py-8`, groups `gap-6`, field block `gap-2`, body `text-sm`.\n- D 6-7: rows 40-48px, cells `px-3 py-2`, body `text-sm`, meta `text-xs text-muted-foreground`.\n\nPresets are work-screen defaults. Overview/dashboard-home, onboarding, auth, and empty states may step up one type-size class and run V 4-5.\n\n## Stack specifics\n\nStack specifics (registries, ports, host conventions) belong in stack overlay skills. This skill is stack-agnostic.\n\n## Token discipline (the single most important rule)\n\nSemantic tokens only: `bg-background`, `bg-card`, `bg-muted`, `text-foreground`, `text-muted-foreground`, `border-border`, `bg-primary text-primary-foreground`, `text-destructive`, `ring-ring`, `bg-sidebar`. Raw palette utilities (`bg-zinc-100`, `text-gray-500`) and hex/oklch literals are BANNED. Missing a token: add it to the theme, never inline. Where a host owns the theme, remotes consume tokens and never redefine them; semantic tokens make dark mode free, so verify `.dark` renders too.\n\n## Nicer than default shadcn\n\nDefault shadcn is a wireframe. Upgrade means:\n\n- Hierarchy via weight, size, `text-muted-foreground`; never decoration.\n- One spacing scale per screen; `divide-y` over wrapping everything in Cards.\n- `tabular-nums` on every numeric column, stat, countdown.\n- Icon + label: `gap-2`, icon `size-4 shrink-0`. Truncating text gets `truncate` + `title`.\n- Row hover `hover:bg-muted/50`. Focus rings never suppressed.\n- Decoration (gradients, illustration, expressive type) lives in empty states, onboarding, auth, zero-data moments - never in work surfaces (tables, forms, toolbars). No decorative animation, scroll effects, or duplicate primitives anywhere.\n\n## Page anatomy\n\nHeader, then toolbar, then content. No hero, no banner, no gradient header: product pages start with work.\n\n- Header: title `text-lg`/`text-xl font-semibold` + optional `text-sm text-muted-foreground` description, actions right, ONE primary.\n- Toolbar: search left, filters middle, view options right.\n- Max 2 heading levels below the page title. Advanced options collapse. Primary action reachable without scrolling or opening menus.\n\n## Widths and alignment\n\n- Tables, dashboards: `w-full`.\n- Forms: `max-w-2xl`, single column. Multi-column field grids are a scanning disaster; paired fields (city/zip) OK.\n- Detail pages: `max-w-4xl` or 2/3 + 1/3 split.\n- ONE left edge for everything. Misaligned edges are the first sign of a careless refactor.\n\n## Container choice\n\n- Comparable records: TABLE, always. Card grids waste 60% of the space.\n- Visually dominant heterogeneous items: card grid.\n- One-line items: `divide-y` list.\n- KPIs: stat row, max 4-5, no decorative icons.\n\n## Buttons\n\n- ONE primary (`default` variant) per view. Everything else `outline`, `ghost`, `secondary`.\n- Destructive: `variant=\"destructive\"` + AlertDialog confirm, always.\n- Labels verb-first, 1-3 words: \"Create user\", not \"Submit\".\n- Icon-only buttons: ALWAYS Tooltip + `aria-label`.\n- Busy state: disabled + spinner + label kept (\"Saving...\").\n\n## Tables\n\n- Structure: toolbar, table, pagination footer (row count + controls).\n- Text left, numbers right with `tabular-nums`, one date format, ONE badge status column.\n- Max 8 visible columns; more goes behind a column-visibility menu.\n- First column = identity, links to detail.\n- Row actions: max 2 ghost icon buttons + kebab menu. Never 5 icons in a row.\n- Header `sticky top-0 bg-background`. Horizontal scroll OK; wrapped cells and squeezed columns are not.\n- Empty cell: \"-\" or \"Not set\", one convention app-wide.\n- Sort state visible; `aria-sort` on sortable headers. Active filters visible as removable chips.\n- Bulk actions appear contextually on selection; no permanently visible disabled buttons.\n\n## Forms\n\n- Max 7 fields per group; group heading `text-sm font-medium` + Separator.\n- Label above, helper `text-xs text-muted-foreground` below, error `text-destructive` below field. Validate on blur or submit, never per keystroke. Placeholders show format examples only, never act as labels.\n- Field width matches content: a zip code is not `w-full`.\n- Mark the minority: if most fields are required, mark optional ones, and vice versa.\n- Semantic input types (`email`, `tel`, `number`) and `autocomplete` attributes.\n- Submit row: one convention locked (e.g. primary right, Cancel ghost left of it). Sticky footer on long forms. After failed submit: focus first invalid field; long forms add an error summary with anchor links.\n- Unsaved-changes guard on navigation.\n- Wizard ONLY for real sequential dependency or >15 fields with phases. A 6-field form in a 3-step wizard is UX vandalism. Wizard = step indicator + back always available + values preserved.\n\n## Overlay decision tree\n\n- Confirm destructive: AlertDialog.\n- 1-5 fields: Dialog (`max-w-md`/`max-w-lg`). 15 fields + tabs in a Dialog is wrong.\n- Edit/inspect while list stays visible: Sheet.\n- Tiny choice, filter, date: Popover.\n- Hint only: Tooltip, never interactive content.\n- Full create flow: dedicated page/route.\n- All overlays: focus trap, Escape closes, focus restored to trigger.\n\n## Feedback\n\n- sonner: transient confirmations only, optional action (Undo, View). Auto-dismiss; do not steal focus. NEVER errors requiring action.\n- Blocking problems: inline `Alert` in context.\n- Validation lives at the field (plus summary on long forms). Toast-only errors are banned.\n- Save success: toast + visible UI state change. No navigate-away without signal, no \"Success!\" interstitial pages.\n- Errors announce via `role=\"alert\"`/`aria-live`.\n\n## Status system\n\nONE status system per app: fixed label + fixed color per state, everywhere. Base on tokens (`--success`, `--warning`, extend theme). Badge restraint: 3 badges per row means none matter. Color is never the only carrier: color + label always, no unlabeled dots.\n\n## Navigation\n\n- Tabs = peer views, URL-backed (`?tab=`), deep-linkable.\n- Breadcrumbs at 2+ levels of hierarchy.\n- Where a host shell owns module navigation, the sidebar lives there; do not rebuild it in the embedded app.\n- Back is safe: filters, search, page, scroll survive detail-and-back. Never silently reset state.\n- Route change moves focus to main content.\n\n## Dashboards and charts\n\n- Every widget answers a concrete question. \"Nice to have a chart\" = delete it.\n- Composition: stat row (max 4-5), one primary visualization, one actionable table.\n- Charts use `--chart-*` tokens, labeled axes with units, visible legend, tooltips with exact values, max 4-6 series. Gridlines low-contrast.\n- Trend: line. Comparison: bar. Proportion: only if 5 or fewer slices; a pie with more is a table wearing a costume. Prefer bar/line over pie.\n- No 3D, no gradient fills, no color-only meaning (pair with labels/patterns), no fake trend arrows, no invented deltas.\n- Aggregate or sample beyond ~1000 points; offer a table alternative for data-heavy or screen-reader needs.\n- Each widget fails alone: inline error + retry inside the widget, dashboard stays alive.\n\n## Type scale (default)\n\n| Role | Class |\n|---|---|\n| Page title | `text-lg` or `text-xl font-semibold` |\n| Section heading | `text-sm font-medium` |\n| Body | `text-sm` |\n| Meta | `text-xs text-muted-foreground` |\n| Dashboard stat number | `text-3xl` (the large-text exception on work screens) |\n\nOverview/dashboard-home, onboarding, auth, and empty states may step up one type-size class and run V 4-5.\n\n## Motion\n\nMotion = feedback only: hover, press, overlay open/close. 150-200ms, `ease-out`, transform/opacity only. NO scroll animation, NO perpetual loops, NO stagger reveals, NO entrance choreography. Honor `prefers-reduced-motion`.\n\n## Responsive\n\nDesktop-first. Must not break at 1024px (minus host sidebar width). Toolbars wrap, sidebars collapse, tables scroll horizontally (never squeeze columns), forms are already single column.\n\n## i18n and formatting\n\nWhere the project uses i18n:\n\n- German runs ~30% longer; `truncate` is not a strategy for button labels. Test long locale.\n- All strings through `t()`. All dates/numbers/currency via `Intl.DateTimeFormat`/`NumberFormat`/`RelativeTimeFormat` with the active locale. Never hand-concatenate date strings.\n- ONE date format per app per locale. Timestamps <7 days old: relative (\"2 hours ago\") + absolute in Tooltip/title; older: absolute (\"12 Mar 2026\").\n- Thousands separators on large numbers; money always 2 decimals; unit once per column header or with every value, never mixed.\n\n## UI states (ship the full cycle)\n\n- Loading: skeleton mirrors the final layout (table = header + N rows). No full-page spinner where a skeleton is possible. Flash discipline: delay appearance 150-200ms, once visible keep >=300ms; an 80ms flash reads as a glitch. Skeleton on FIRST load only.\n- Empty, no data: composed state with explanation + permission-aware primary action.\n- Empty, filtered: different message + \"Clear filters\" action. Never confuse the two.\n- Error: inline, chrome stays alive, Retry button, correlation/request ID in `text-xs text-muted-foreground`.\n- Mutations: disable submit while pending, preserve user input on failure.\n- Optimistic updates only with rollback + low conflict risk (toggles, favorites).\n- Query pattern: `isPending` skeleton, `isError` ErrorState(refetch), empty EmptyState, else data.\n\n## Error copy formula\n\n1. What happened, plain: \"Couldn't save the supplier\".\n2. Why, if useful: \"A supplier with this name already exists\".\n3. What to do next: Retry, corrective action, or support + request ID.\n\nBanned: \"Something went wrong\" without an action, raw `ConnectError: [internal]` dumps, error codes as content.\n\n## Data mechanics\n\n- Filter/sort/page state lives in the URL (`useSearchParams`): deep-linkable, survives back-nav. In-memory filter state is a bug. Filter or sort change resets the `page` param; use `replace: true`.\n- Search input updates instantly, query debounced ~300ms; show an inline hint, not a full-table skeleton.\n- Pagination: `placeholderData: keepPreviousData`; dim stale data via `isPlaceholderData` (`opacity-60`).\n- Server vs client: <=~1k rows loaded, filter/sort/paginate client-side; larger, server-side keyed on URL params. NEVER client-filter a server-paginated list: it filters the visible page and silently lies.\n- Virtualize client lists above ~200 rendered rows (`@tanstack/react-virtual`). Prefer real pagination over infinite scroll for record management.\n- Persist harmless view prefs (column visibility, density, page size) in localStorage. NEVER silently persist filters across sessions.\n\n## Shared components\n\nRule of two: the second time a composition appears in a frontend, extract to `src/components/` (never `components/ui/`, that is registry-owned). The second frontend that needs it: propose promotion to the shared component registry. Big four every module needs: `PageHeader`, `EmptyState`, `ErrorState`, `TableSkeleton`. Canonical code + `useTableUrlState`, `useDebounced`, query pattern: see `references/components.md`.\n\n## Destructive operations\n\n- Every destructive action: AlertDialog confirm. sonner-undo alone is not consent for irreversible ops.\n- High blast radius (project, company, cascading delete): type-to-confirm, user types the resource name.\n- Bulk destructive: confirm with count (\"Delete 3 users?\").\n- Cross-page selection honesty: \"select all\" means the visible page; \"select all N matching\" is a separate explicit action passing the FILTER to the backend, not an ID list. Never fake 5000 selected with 25 IDs in memory.\n\n## Save model\n\nPick ONE per screen: explicit Save (entity forms) OR auto-save with visible status (\"Saving...\", \"Saved\"; settings toggles). Never mixed, never half-auto.\n\n## Permissions\n\n- HIDE actions the role can never perform.\n- DISABLE temporarily unavailable actions + Tooltip explaining why (\"Requires manager approval\").\n- Layout stays stable across roles: no column shifting, no reflowing grids.\n- Empty-state CTA is permission-aware.\n- UI gating is UX, not security; backend authorization enforces permission decisions.\n\n## Long-running operations\n\n- >~2s expected: determinate `Progress` if the backend reports progress, else an honest label (\"Importing 1,240 rows...\").\n- >~10s: do not hold the UI hostage. Fire, show a persistent status affordance (badge \"Processing\"), poll/refetch, toast on completion. NEVER a frozen modal spinner with no escape.\n\n## Refactor protocol\n\nAudit before touching:\n\n1. Behavior inventory: every interaction becomes the regression checklist.\n2. Data contracts, routes/params, i18n keys.\n3. Sibling conventions: migrate ALL screens or none.\n\nLever order: spacing/alignment, hierarchy, tokens, states, component correctness, structural change (last, with approval). Never silently change: routes, query params, field names, API calls, i18n keys, host-owned theme/nav.\n\n## Banned in product UI\n\nDecoration (gradients, glassmorphism, illustration, expressive type) in work surfaces (tables, forms, toolbars); it belongs in empty states, onboarding, auth, and zero-data moments only. Scroll-triggered animation, perpetual loops, stagger reveals anywhere. Marketing sections in apps. Raw palette classes and inline hex. Custom fonts or host-token overrides where the host owns the theme. Placeholder-as-label. Two primary buttons; duplicate CTA intent. Unconfirmed deletes. Toast-only errors. Five row-action icons; wrapped cells; squeezed columns. Permanent disabled bulk buttons; dishonest cross-page select-all. Client-filtering server-paginated lists. Filters silently persisted. In-memory-only filter state. Disabled controls without tooltip; visible never-permitted actions; permission-dependent layout shifts. Pies over 5 slices; fake deltas; questionless charts. Hand-built date strings; mixed date formats. Card grids for comparable records. `truncate` on button labels. Generic spinner where skeleton fits; full-page spinner; skeleton flash <150ms; per-page-turn skeletons. Frozen modal for long ops. Mixed save models. Suppressed focus rings. Emojis in UI. Em-dashes and en-dashes in any visible string (ranges use hyphens). \"Should render fine\" without verification.\n\n## Verification\n\nNever claim done from code alone. Run the `frontend-qa` loop at the tier matching the change (its section 0). New screens, new layouts, state work, and redesigns get the full browser loop: render the real app, screenshot + a11y snapshot in BOTH themes, widths 1280 and 1024, forced state walk (loading/empty/error), tab-through, zero new console errors. Trivial tweaks (a copy edit, one token or class change) drop to the static-only tier per the frontend-qa tier table - no browser required. When a host shell exists, verify the embedded context and standalone application. If the stack is not running, say \"untested: stack not running\".\n\n## Pre-flight (before declaring done)\n\n- Screen read stated; dials set and spacing locked.\n- Semantic tokens only; both themes verified.\n- One primary action; destructive actions confirmed.\n- Full state cycle shipped: loading (delayed skeleton), empty x2, error with retry.\n- URL holds filter/sort/page; back-nav restores state.\n- All strings through `t()`; Intl formatting; one date format.\n- Alignment: one left edge; `tabular-nums` on numbers.\n- No banned patterns from the list above.\n",
|
|
14
|
+
"kind": "skill-md"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"path": "references/components.md",
|
|
18
|
+
"content": "# product-ui canonical components and data hooks\n\nThe \"big four\" plus data hooks. Copy into the remote's `src/components/` (never `components/ui/`, that folder is registry-owned). In real code every visible string goes through `t(...)`; literals below are for brevity. Semantic tokens only.\n\n## PageHeader\n\n```tsx\nimport type { ReactNode } from \"react\";\n\ninterface PageHeaderProps {\n title: string;\n description?: string;\n /** Right-side actions. ONE primary button max. */\n children?: ReactNode;\n}\n\nexport function PageHeader({ title, description, children }: PageHeaderProps) {\n return (\n <div className=\"flex flex-wrap items-start justify-between gap-4 pb-6\">\n <div className=\"space-y-1\">\n <h1 className=\"text-xl font-semibold tracking-tight\">{title}</h1>\n {description && (\n <p className=\"text-sm text-muted-foreground\">{description}</p>\n )}\n </div>\n {children && <div className=\"flex items-center gap-2\">{children}</div>}\n </div>\n );\n}\n```\n\n## EmptyState\n\nTwo variants by usage: no data yet (explanation + permission-aware CTA) vs no filter matches (offer \"Clear filters\"). Never confuse them.\n\n```tsx\nimport type { LucideIcon } from \"lucide-react\";\nimport type { ReactNode } from \"react\";\n\ninterface EmptyStateProps {\n icon: LucideIcon;\n title: string;\n description?: string;\n /** Permission-aware: hide if the role can never create. */\n action?: ReactNode;\n}\n\nexport function EmptyState({ icon: Icon, title, description, action }: EmptyStateProps) {\n return (\n <div className=\"flex flex-col items-center justify-center py-16 text-center\">\n <div className=\"flex size-12 items-center justify-center rounded-full bg-muted\">\n <Icon className=\"size-6 text-muted-foreground\" />\n </div>\n <h2 className=\"mt-4 text-sm font-medium\">{title}</h2>\n {description && (\n <p className=\"mt-1 max-w-sm text-sm text-muted-foreground\">{description}</p>\n )}\n {action && <div className=\"mt-4\">{action}</div>}\n </div>\n );\n}\n```\n\n## ErrorState\n\nError copy formula: what happened, why if useful, what to do next. Request ID for support. Never raw `ConnectError` dumps.\n\n```tsx\nimport { AlertCircle } from \"lucide-react\";\nimport { Button } from \"@/components/ui/button\";\n\ninterface ErrorStateProps {\n /** What happened, plain: \"Couldn't load suppliers\". */\n title: string;\n /** Why, if useful: \"The service did not respond\". */\n detail?: string;\n /** Correlation ID from the RPC error, for support. */\n requestId?: string;\n onRetry?: () => void;\n}\n\nexport function ErrorState({ title, detail, requestId, onRetry }: ErrorStateProps) {\n return (\n <div className=\"flex flex-col items-center justify-center py-16 text-center\" role=\"alert\">\n <div className=\"flex size-12 items-center justify-center rounded-full bg-destructive/10\">\n <AlertCircle className=\"size-6 text-destructive\" />\n </div>\n <h2 className=\"mt-4 text-sm font-medium\">{title}</h2>\n {detail && (\n <p className=\"mt-1 max-w-sm text-sm text-muted-foreground\">{detail}</p>\n )}\n {onRetry && (\n <Button variant=\"outline\" size=\"sm\" className=\"mt-4\" onClick={onRetry}>\n Retry\n </Button>\n )}\n {requestId && (\n <p className=\"mt-4 text-xs text-muted-foreground\">Request ID: {requestId}</p>\n )}\n </div>\n );\n}\n```\n\n## TableSkeleton\n\nMirrors the final table layout (header + N rows). Flash discipline built in: invisible for 150ms, fades in over 200ms. Use on FIRST load only; page turns keep previous data dimmed instead.\n\n```tsx\nimport { Skeleton } from \"@/components/ui/skeleton\";\n\ninterface TableSkeletonProps {\n columns?: number;\n rows?: number;\n}\n\nexport function TableSkeleton({ columns = 5, rows = 8 }: TableSkeletonProps) {\n return (\n <div className=\"animate-in fade-in fill-mode-forwards opacity-0 delay-150 duration-200 space-y-2\">\n <div className=\"flex gap-4 border-b pb-3\">\n {Array.from({ length: columns }).map((_, i) => (\n <Skeleton key={i} className=\"h-4 flex-1\" />\n ))}\n </div>\n {Array.from({ length: rows }).map((_, r) => (\n <div key={r} className=\"flex gap-4 py-1\">\n {Array.from({ length: columns }).map((_, c) => (\n <Skeleton key={c} className=\"h-8 flex-1\" />\n ))}\n </div>\n ))}\n </div>\n );\n}\n```\n\n## useTableUrlState\n\nFilter/sort/page live in the URL: deep-linkable, survives back-nav. Filter or sort change deletes `page`. `replace: true` keeps history clean while typing.\n\n```tsx\nimport { useSearchParams } from \"react-router-dom\";\n\nexport function useTableUrlState() {\n const [searchParams, setSearchParams] = useSearchParams();\n\n const filter = searchParams.get(\"filter\") ?? \"\";\n const sort = searchParams.get(\"sort\") ?? \"\";\n const page = Number(searchParams.get(\"page\") ?? \"1\");\n\n const update = (patch: Record<string, string | null>) => {\n setSearchParams(\n (prev) => {\n const next = new URLSearchParams(prev);\n for (const [key, value] of Object.entries(patch)) {\n if (value === null || value === \"\") next.delete(key);\n else next.set(key, value);\n }\n if (\"filter\" in patch || \"sort\" in patch) next.delete(\"page\");\n return next;\n },\n { replace: true },\n );\n };\n\n return { filter, sort, page, update };\n}\n```\n\n## useDebounced\n\nInput state updates instantly; the query key debounces ~300ms.\n\n```tsx\nimport { useEffect, useState } from \"react\";\n\nexport function useDebounced<T>(value: T, delay = 300): T {\n const [debounced, setDebounced] = useState(value);\n useEffect(() => {\n const id = setTimeout(() => setDebounced(value), delay);\n return () => clearTimeout(id);\n }, [value, delay]);\n return debounced;\n}\n```\n\n## Canonical query pattern\n\nSkeleton on first load only; `keepPreviousData` + dim on page turns; empty-no-data vs empty-filtered distinguished; widget-local error with retry.\n\n```tsx\nimport { keepPreviousData } from \"@tanstack/react-query\";\nimport { useQuery } from \"@connectrpc/connect-query\";\nimport { Package, SearchX } from \"lucide-react\";\n\nconst debouncedFilter = useDebounced(filter, 300);\n\nconst { data, isPending, isError, refetch, isPlaceholderData } = useQuery(\n listSuppliers,\n { filter: debouncedFilter, sort, page },\n { placeholderData: keepPreviousData },\n);\n\nif (isPending) return <TableSkeleton columns={6} />;\nif (isError) {\n return <ErrorState title={t(\"suppliers.loadError\")} onRetry={() => refetch()} />;\n}\nif (data.items.length === 0) {\n return hasActiveFilters ? (\n <EmptyState\n icon={SearchX}\n title={t(\"common.noMatches\")}\n action={\n <Button variant=\"outline\" onClick={clearFilters}>\n {t(\"common.clearFilters\")}\n </Button>\n }\n />\n ) : (\n <EmptyState\n icon={Package}\n title={t(\"suppliers.emptyTitle\")}\n description={t(\"suppliers.emptyHint\")}\n action={canCreate && <CreateSupplierButton />}\n />\n );\n}\nreturn (\n <div className={isPlaceholderData ? \"opacity-60\" : undefined}>\n <SuppliersTable data={data.items} />\n </div>\n);\n```\n",
|
|
19
|
+
"kind": "raw"
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"name": "python-dev",
|
|
4
|
+
"type": "skill",
|
|
5
|
+
"title": "Python development",
|
|
6
|
+
"description": "Modern Python development. Use when writing or reviewing any Python code, setting up uv environments, linting with ruff, typing with mypy/pyright, writing pytest suites, or packaging and publishing to PyPI.",
|
|
7
|
+
"files": [
|
|
8
|
+
{
|
|
9
|
+
"path": "SKILL.md",
|
|
10
|
+
"content": "---\nname: python-dev\nlabel: \"Python development\"\ndependencies: [python3]\ndescription: >\n Modern Python development. Use when writing or reviewing any Python code,\n setting up uv environments, linting with ruff, typing with mypy/pyright,\n writing pytest suites, or packaging and publishing to PyPI.\n---\n\nModern Python: uv for everything env, ruff for everything style, types everywhere.\n\n## Environment & packaging\n\n- `uv` first: `uv init`, `uv add`, `uv run` (falls back: `python3 -m venv .venv` + pip). Never install into the system interpreter.\n- `pyproject.toml` is the single config file (project metadata, ruff, pytest, mypy sections); no setup.py, no requirements.txt for new projects.\n- src layout: `src/<package>/`, tests in `tests/` — prevents accidental imports of the working directory.\n- Pin via lockfile (`uv.lock`); CI installs frozen.\n\n## Code style\n\n- Type hints on every public function; `mypy --strict` or pyright clean.\n- `ruff check` + `ruff format` replace flake8/isort/black — one tool, configured in pyproject.\n- Lint loop: `ruff check --fix`, review the diff, then `--unsafe-fixes` only with diff review, `ruff format`, re-check until clean. Suppress with narrow `# noqa: <RULE>` plus a reason — never bare `# noqa`, never to dodge a refactor the rule is right about.\n- Dataclasses (or pydantic at IO boundaries) over dict-shaped data; `pathlib.Path` over `os.path`; f-strings over %/format.\n- Exceptions: one package base (`class FooError(Exception)`) with specific subclasses; raise the narrow one, never bare `except:`; context managers for resources.\n\n## Testing\n\n- pytest, plain asserts, fixtures over setup methods; `tmp_path` for filesystem work.\n- Parametrize instead of copy-pasted tests; mark slow/integration tests for selection.\n- Test behavior at the public boundary; mock only true externals (network, clock).\n- Coverage: `pytest --cov --cov-report=term-missing` shows exactly which lines lack tests; chase the meaningful gaps (branches, error paths), not a vanity 100%.\n\n## Libraries & publishing\n\n- Ship types: empty `py.typed` marker inside the package (PEP 561) — without it, consumers' type checkers ignore all your hints.\n- Library deps are `>=` minimums; upper bounds only for known breakage; exact pins (`==`) belong in applications, never libraries.\n- Single version source: derive from git tags (`hatch-vcs`/`setuptools_scm`) or one `__version__`; read it via `importlib.metadata.version(...)`, never maintain it in two places.\n- License as SPDX string (`license = \"MIT\"`, PEP 639). Build `uv build` (sdist + wheel), validate `twine check dist/*`, publish from CI via Trusted Publishing (OIDC) — no long-lived API tokens.\n\n## Runtime habits\n\n- `logging` (or structlog) over print; configure once at the entrypoint.\n- Entrypoints via `[project.scripts]` in pyproject, not `if __name__ == \"__main__\"` scattered around.\n- Subprocesses with `subprocess.run([...], check=True, capture_output=True)` — lists, never shell strings.\n",
|
|
11
|
+
"kind": "skill-md"
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"standalone": false,
|
|
15
|
+
"meta": {
|
|
16
|
+
"systemDependencies": [
|
|
17
|
+
"python3"
|
|
18
|
+
]
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"name": "react-dev",
|
|
4
|
+
"type": "skill",
|
|
5
|
+
"title": "React development",
|
|
6
|
+
"description": "React component development. Use when writing or reviewing any React code, composing components and hooks, fetching data server or client side, adopting React 19 APIs, or testing React UI.",
|
|
7
|
+
"files": [
|
|
8
|
+
{
|
|
9
|
+
"path": "SKILL.md",
|
|
10
|
+
"content": "---\nname: react-dev\nlabel: \"React development\"\ndependencies: [node]\ndescription: >\n React component development. Use when writing or reviewing any React code,\n composing components and hooks, fetching data server or client side, adopting\n React 19 APIs, or testing React UI.\n---\n\nReact is a function of state — keep state minimal, derived values computed, effects rare.\n\n## Components\n\n- Function components only; small, single-purpose, composed via children/slots over prop drilling.\n- Props: explicit interface, destructured, no `React.FC`; discriminated unions for variant props instead of boolean soup.\n- Colocate: component + styles + test + story live together; promote to shared only on the second consumer.\n\n## State & hooks\n\n- State as low as possible, lifted only when shared; derive instead of syncing (`const full = first + last`, not a third useState).\n- `useEffect` is for synchronizing with external systems ONLY — not for transforming data (compute in render) and not for reacting to state changes (do it in the event handler).\n- Every effect: complete dependency array, cleanup function, and a one-line comment naming the external system it syncs.\n- Server cache ≠ client state: data fetching via TanStack Query/SWR/framework loaders (caching, retries, invalidation), client UI state via useState/useReducer/zustand. Context for low-frequency globals (theme, auth), not as a store.\n\n## React 19+ API surface\n\nOn React 19, prefer the new surface; don't backport these onto 18 codebases.\n\n- `ref` is a regular prop — no `forwardRef`; ref callbacks may return a cleanup function (replaces null-check teardown).\n- Render context directly: `<Ctx value={...}>` instead of `<Ctx.Provider value={...}>`.\n- Forms via Actions: `<form action={fn}>` + `useActionState` for result/error state, `useFormStatus` for pending UI in the submit button, `useOptimistic` for instant feedback reconciled with the server result.\n- `use(promise)` inside a Suspense boundary for async data — promise created outside render (cached/loader), never inline in the component body.\n- Document metadata (`<title>`, `<meta>`, `<link>`) can live in components; React hoists them to `<head>`.\n\n## Rendering correctness\n\n- Stable `key`s from data identity, never array index on mutable lists.\n- Mark non-urgent updates as transitions (`useTransition`/`startTransition`: filtering, tab switches, big list updates); `useDeferredValue` for expensive rendering derived from fast-changing input.\n- All `setState` is batched (timeouts, promises, native handlers included); `flushSync` only when an intermediate paint must be user-visible — it bypasses the scheduler.\n- memo/useMemo/useCallback only for measured problems or referential-equality requirements — not by default (and redundant under React Compiler).\n- Code-split at route boundaries (`lazy` + `Suspense`); error boundaries around risky subtrees.\n\n## Accessibility & testing\n\n- Semantic elements first (`button`, `nav`, `label for`); ARIA only where semantics fall short; everything keyboard-reachable.\n- React Testing Library: query by role/label like a user; test behavior, not implementation; `userEvent` over `fireEvent`.\n- React 19: `import { act } from 'react'` (`react-dom/test-utils` is removed, `Simulate` → RTL `fireEvent`); StrictMode no longer double-invokes effects in dev — measure spy call counts, don't assume doubled.\n- Forms: controlled inputs or form libs (react-hook-form), with validation errors tied to fields via `aria-describedby`.\n",
|
|
11
|
+
"kind": "skill-md"
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"standalone": false,
|
|
15
|
+
"meta": {
|
|
16
|
+
"systemDependencies": [
|
|
17
|
+
"node"
|
|
18
|
+
]
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"name": "resolving-merge-conflicts",
|
|
4
|
+
"type": "skill",
|
|
5
|
+
"title": "Resolving merge conflicts",
|
|
6
|
+
"description": "Resolve an in-progress git merge or rebase conflict. Use when a merge/rebase is halted on conflicting hunks and you need to finish it to a clean commit.",
|
|
7
|
+
"files": [
|
|
8
|
+
{
|
|
9
|
+
"path": "SKILL.md",
|
|
10
|
+
"content": "---\nname: resolving-merge-conflicts\nlabel: \"Resolving merge conflicts\"\nsource: https://github.com/mattpocock/skills\ndescription: >\n Resolve an in-progress git merge or rebase conflict. Use when a merge/rebase\n is halted on conflicting hunks and you need to finish it to a clean commit.\n---\n\n<!-- Adapted from mattpocock/skills (MIT, (c) 2026 Matt Pocock) -->\n\n1. **See the current state** of the merge/rebase. Check git history, and the conflicting files.\n\n2. **Find the primary sources** for each conflict. Understand deeply why each change was made, and what the original intent was. Read the commit messages, check the PRs, check original issues/tickets.\n\n3. **Resolve each hunk.** Preserve both intents where possible. Where incompatible, pick the one matching the merge's stated goal and note the trade-off. Do **not** invent new behaviour. Always resolve; never `--abort`.\n\n4. Discover the project's **automated checks** and run them — typically typecheck, then tests, then format. Fix anything the merge broke.\n\n5. **Finish the merge/rebase.** Stage everything and commit. If rebasing, continue the rebase process until all commits are rebased.\n",
|
|
11
|
+
"kind": "skill-md"
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"standalone": false,
|
|
15
|
+
"meta": {
|
|
16
|
+
"source": "https://github.com/mattpocock/skills"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"name": "scratchpad",
|
|
4
|
+
"type": "skill",
|
|
5
|
+
"title": "scratchpad (handoff convention)",
|
|
6
|
+
"description": "Shared scratchpad convention for agent handoff: session-namespaced notes in .opencode/scratchpad.json; tool on opencode, file convention elsewhere.",
|
|
7
|
+
"dependencies": [
|
|
8
|
+
"tool:scratchpad"
|
|
9
|
+
],
|
|
10
|
+
"files": [
|
|
11
|
+
{
|
|
12
|
+
"path": "SKILL.md",
|
|
13
|
+
"content": "---\nname: scratchpad\ndescription: >\n Shared scratchpad for agent handoff: scout stores summaries/plans, developer\n and expert read them instead of re-reading raw files. Use when handing off\n between agents, or before re-reading anything another agent already\n summarized. Notes are namespaced per session.\n---\n\n# Scratchpad — cheap context handoff\n\nOne store, many agents. Write once, read cheap. Always check the scratchpad\nbefore re-reading files another agent may have summarized.\n\n## Where\n\n`.agents/scratchpad.json` in the project root — one store shared by ALL\nframeworks, so notes flow between them. Shape:\n\n```json\n{ \"<sessionId>\": { \"<key>\": { \"text\": \"...\", \"updatedAt\": \"ISO\", \"agent\": \"scout\" } } }\n```\n\nNotes are namespaced by **session id** so parallel sessions never collide.\nReads fall back to other sessions when the key is missing in yours\n(cross-session handoff).\n\n## How\n\nOne shared core, one store — three native interfaces:\n\n- **opencode**: use the `scratchpad` tool (plugin SDK; actions `set` / `get` /\n `list`, `list` with `scope=all`). Session id injected automatically.\n- **Claude Code**: use the `scratchpad` MCP tool (registered in `.mcp.json`,\n same actions). Session id from env automatically.\n- **other frameworks** (Copilot, Codex, KiloCode, Hermes): a scratchpad CLI\n is installed in your framework's tools dir (`.github/tools/`,\n `.codex/tools/`, `.kilocode/tools/`, `.hermes/tools/`). Run it via shell:\n\n ```bash\n bun <tools-dir>/scratchpad.ts set auth-flow-summary \"JWT in middleware, expiry check src/auth.ts:42\" --session <id>\n bun <tools-dir>/scratchpad.ts get auth-flow-summary --session <id>\n bun <tools-dir>/scratchpad.ts list --all\n ```\n\n Session id, first match wins: `--session` flag → `$AGENT_SESSION_ID` →\n `$CLAUDE_SESSION_ID` → `default`. When your framework exposes none, the\n orchestrator announces a session key at session start\n (`<yyyy-mm-dd>-<short-task-slug>`); pass it via `--session`.\n Set `$AGENT_NAME` so notes carry their author. Never edit the JSON by\n hand — the tools merge safely across sessions.\n\n## Conventions\n\n- Keys: kebab-case, content-addressed: `auth-flow-summary`, `refactor-plan`,\n `expert-verdict-db-migration`.\n- Values: caveman ultra. Summaries ≤ 10 lines. `file:line` refs exact.\n- scout writes after every read/summarize task. developer/expert check\n `get`/`list` before reading raw files. Orchestrator references keys in\n delegation prompts (\"ctx in scratchpad: auth-flow-summary\") instead of\n pasting content.\n- Stale notes (file changed since `updatedAt`): verify before trusting; mark\n refreshed notes by overwriting the same key.\n\n## Handoff quality\n\nA note is a handoff to the next agent. Make it land:\n\n- **Reference, never copy.** Point at artifacts by path/URL/`file:line`/key.\n Never paste file contents, diffs, or logs into a note — the reader opens the\n source.\n- **Redact secrets/PII.** No tokens, keys, credentials, personal data in notes.\n- **Name next skills.** List the skills the next session should load\n (\"load: product-ui, frontend-qa\").\n- **Tailor to purpose.** Write to the stated goal of the next session — keep\n what that task needs, drop the rest.\n",
|
|
14
|
+
"kind": "skill-md"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"name": "skill-authoring",
|
|
4
|
+
"type": "skill",
|
|
5
|
+
"title": "Skill authoring",
|
|
6
|
+
"description": "Writing and editing agent skills. Use when creating a new skill, rewriting a skill description, restructuring or pruning skill content, or reviewing skills in catalog/content/skills/.",
|
|
7
|
+
"files": [
|
|
8
|
+
{
|
|
9
|
+
"path": "SKILL.md",
|
|
10
|
+
"content": "---\nname: skill-authoring\nlabel: \"Skill authoring\"\nsource: https://github.com/mattpocock/skills\ndescription: >\n Writing and editing agent skills. Use when creating a new skill, rewriting a\n skill description, restructuring or pruning skill content, or reviewing skills\n in catalog/content/skills/.\n---\n\n<!-- Adapted from mattpocock/skills (MIT, (c) 2026 Matt Pocock) -->\n\n# Skill Authoring\n\nA skill wrangles determinism out of a stochastic system. **Predictability** —\nthe agent taking the same *process* every run, not the same output (a\nbrainstorm skill predictably diverges) — is the root virtue every lever serves.\n**Bold terms** are defined in the glossary appendix; the sections below are the\nrules, the appendix the definitions.\n\n## Invocation\n\nTwo ways to reach a skill, each spending a different load:\n\n- **Model-invoked** — keeps a **description**, so the agent (and other skills)\n fire it. Pays **context load**: the description sits in the window every turn.\n In opencode ≈ a rich skill **description**.\n- **User-invoked** — no agent trigger; only a human reaches it. Zero context\n load, spends **cognitive load** (the human is the index). In opencode ≈ a\n **command**.\n\nPick model-invocation only when the agent or another skill must reach it on its\nown. Past what a human can track, a **router** naming the rest cures the pile-up.\n\n## Writing the description\n\nTwo jobs: say what the skill is, list the **branches** that trigger it. Every\nword is context load — prune it harder than the body.\n\n- **Front-load the leading word** — the description does its invocation work.\n- **One trigger per branch.** Synonyms renaming one branch are **duplication**\n (\"test-first … TDD … red-green\" = one branch thrice). Keep distinct branches.\n- **Cut identity already in the body.** Triggers plus any \"when another skill\n needs…\" reach clause. Nothing more.\n\n## Information hierarchy\n\nContent is **steps** and **reference**, mixed freely, ranked by how immediately\nthe agent needs it:\n\n1. **In-skill step** — an ordered action, the primary tier. Each ends on a\n **completion criterion**: *checkable* (done vs not-done?) and, where it\n matters, *exhaustive* (\"every modified model accounted for\", not \"produce a\n change list\"). Vague criteria invite **premature completion**.\n2. **In-skill reference** — a rule or fact on demand. Often a legitimately flat\n peer-set (every review rule on one rung) — fine, not a smell.\n3. **External reference** — pushed to a file behind a **context pointer**,\n loaded only when it fires.\n\nPush too little down and the top bloats; push too much and you hide what the\nagent needs — that tension is the whole decision. A demanding criterion drives\nthorough **legwork** for flat reference as for steps (\"every rule applied\"\nbinds a peer-set as \"every step done\" binds a sequence).\n\n**Progressive disclosure** moves reference down the ladder so the top stays\nlegible; **branching** is the test — inline what every branch needs, disclose\nwhat only some reach. A **context pointer**'s *wording*, not its target, decides\nwhen and how reliably the agent reaches: a must-have behind a weak pointer is a\nvariance bug — sharpen wording first, inline only if that fails.\n**Co-location**: keep a concept's definition, rules, and caveats under one\nheading so reading one part brings its neighbours.\n\n*This skill is mostly reference; its glossary is disclosed to the appendix.*\n\n## When to split\n\n**Granularity** — each cut spends a load, so split only when it earns it:\n\n- **By invocation** — split off a model-invoked skill for a distinct **leading\n word** that should trigger it, or reach another skill needs. Pay context load\n for the new always-loaded description.\n- **By sequence** — split a step run when later **post-completion steps** tempt\n the agent to rush the one in front. Hiding them across a real context boundary\n (hand-off / subagent) buys more legwork on the current step.\n\n## Item-owned AGENTS.md fragments\n\nA skill/agent/tool may require a rule (`rules: [...]`) whose fragment lands in\nthe shared AGENTS.md block, loaded EVERY session for every agent. Spend that\nbudget only on always-on behaviour or cross-cutting policy (caveman mode,\nrouting) — never task-specific guidance, which belongs in the skill body behind\nits own **description** trigger. Keep fragments tiny: a few lines, no lists,\nno examples.\n\n## Pruning\n\n- **Single source of truth** — each meaning in one authoritative place; changing\n behaviour is a one-place edit. **Duplication** violates it.\n- **Relevance** — does the line still bear on what the skill does? Drop stale and\n merely-expository lines.\n- **No-op test**, sentence by sentence — does it change behaviour versus the\n model's default? When one fails, delete the whole sentence, don't trim words.\n Be aggressive; most failing prose should go.\n\n## Leading words\n\nA **leading word** is a compact pretrained concept the agent thinks with while\nrunning the skill (*lesson*, *fog of war*, *tracer bullets*, *red* loop).\nRepeated as a token, never restated as a sentence, it anchors a region of\nbehaviour in the fewest tokens by recruiting priors the model already holds —\n*execution* in the body, *invocation* in the description (shared language in\nprompts/docs/code fires the skill more reliably). Hunt restatements it retires:\n\"fast, deterministic, low-overhead\" → a *tight* loop; \"a loop you believe in\" →\nthe loop goes *red*. Prefer an existing word; a coined one recruits no priors.\n\n## Failure modes\n\nDiagnose against these (each cured by the lever above):\n\n- **Premature completion** — ending a step early. Sharpen the criterion first\n (cheap, local); only if irreducibly fuzzy *and* you see the rush, hide\n post-completion steps by splitting.\n- **Duplication** — one meaning in two places; inflates its rank on the ladder.\n- **Sediment** — stale layers that settle because adding feels safe, removing\n risky. The default fate without pruning.\n- **Sprawl** — too long even when every line is live. Cure with the ladder:\n disclose reference, split by branch or sequence.\n- **No-op** — a line the model already obeys. A weak leading word (*be thorough*)\n is one; fix with a stronger word (*relentless*), not a new technique.\n- **Negation** — steering by prohibition backfires (*don't think of an elephant*\n names it). Prompt the **positive**; keep a ban only as a guardrail you can't\n phrase positively, paired with what to do instead.\n\n---\n\n## Glossary appendix\n\nDisclosed reference for the terms above. **Bold** cross-refs point at other\nentries here. *(Full domain model: mattpocock/skills `writing-great-skills/GLOSSARY.md`.)*\n\n- **Predictability** — the agent behaving the same *way* each run (same process,\n not same output). The root virtue; cost and maintainability are symptoms of\n it, not rivals.\n- **Model-invoked** — keeps its **description**, so the agent fires it\n autonomously and other skills reach it (human reach always included). Pays\n **context load** for that discoverability.\n- **User-invoked** — description stripped; only the human reaches it, no other\n skill can. Trades discoverability for zero **context load**.\n- **Description** — the machine-readable trigger; its mere presence *is* the\n invocation axis. Keep it → model-invoked; drop it → **user-invoked**.\n- **Context pointer** — a reference in context naming out-of-context material\n plus the condition to reach it. The **description** is the top-level one. Its\n *wording*, not the target, decides when and how reliably the agent reaches.\n- **Context load** — the cost a **model-invoked** skill imposes on the window\n (its always-loaded **description**). The brake on adding model-invoked skills.\n- **Cognitive load** — the cost a **user-invoked** skill imposes on the human\n (remembering it exists and when to reach). Not to be minimised: the price of\n human agency. The brake on adding user-invoked skills.\n- **Router** — a **user-invoked** skill that points at the others, curing\n **cognitive load** when they multiply. Can hint, never fire them.\n- **Granularity** — how finely skills divide; each cut spends **context** or\n **cognitive load**. Cut by **invocation** or by **sequence**.\n- **Information hierarchy** — content ranked by how immediately it is needed:\n **steps** (primary), in-file **reference**, disclosed reference.\n- **Steps** — the ordered actions the agent performs; the tier that earns its\n place in the body. Each ends on a **completion criterion**.\n- **Reference** — material consulted on demand (rules, facts, examples).\n Secondary to **steps** when present; the prime candidate for **progressive\n disclosure**.\n- **Progressive disclosure** — moving **reference** down the ladder behind a\n **context pointer** so the top stays legible. Licensed by **branching**.\n- **Co-location** — keeping a concept's definition, rules, and caveats together\n so reading one part brings its neighbours. Distinct from **duplication** (one\n meaning twice) — co-location fixes one meaning *scattered*.\n- **Branch** — a distinct way a skill is invoked, so different runs take\n different paths. The disclosure test: inline what every branch needs.\n- **Leading word** — a pretrained concept the agent thinks with; repeated as a\n token it anchors behaviour in the fewest tokens. Anchors **execution** in the\n body, **invocation** in the description.\n- **Completion criterion** — the condition that says a unit of work is done. Its\n *clarity* resists **premature completion** (needs steps to bite); its *demand*\n sets **legwork** (binds flat reference too). Strongest criteria are checkable\n and exhaustive.\n- **Legwork** — the digging an agent does within a step (reading, exploring,\n changing) rather than offloading to the user. Raised by a **leading word** or\n a demanding **completion criterion**.\n- **Post-completion steps** — the steps after the current one. Visible, they\n pull the agent into **premature completion**; the defence is to hide them by\n splitting.\n- **Premature completion** — *failure mode.* Ending a step before it is done, as\n attention slips to being done. A between-steps failure: fuzziness is the\n necessary condition, visible **post-completion steps** the pull.\n- **Negation** — *failure mode.* Steering by prohibition, which drags the\n forbidden behaviour into context and makes it *more* available. Cure: prompt\n the **positive**; keep a ban only as an unphraseable guardrail, paired with\n the target.\n- **Single source of truth** — each meaning in exactly one authoritative place.\n **Duplication** is its violation.\n- **Duplication** — *failure mode.* One meaning given more than one home. Costs\n maintenance, tokens, and inflated rank. The accidental inverse of a **leading\n word** (which repeats a *token*, never the meaning).\n- **Relevance** — whether a line still bears on what the skill does. Lost by\n never bearing (exposition, a branch that should be disclosed) or by going\n stale. Distinct from **no-op** (behaviour vs default, not bearing vs task).\n- **Sediment** — *failure mode.* Stale layers that settle because adding feels\n safe and removing risky. The default fate without pruning.\n- **Sprawl** — *failure mode.* A skill too long even when every line is live and\n unique. Cured by the **information hierarchy**.\n- **No-op** — *failure mode.* A line the model already obeys by default. Test:\n does it change behaviour versus the default? Model-relative — settle disputes\n by running the skill, not debate.\n",
|
|
11
|
+
"kind": "skill-md"
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"meta": {
|
|
15
|
+
"source": "https://github.com/mattpocock/skills"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"name": "software-design",
|
|
4
|
+
"type": "skill",
|
|
5
|
+
"title": "Software design (deep modules)",
|
|
6
|
+
"description": "Shared vocabulary for designing deep modules: interfaces, seams, depth, adapters, the deletion test. Use when designing or improving a module's interface, deciding where a seam goes, making code more testable, or when another skill needs the deep-module language.",
|
|
7
|
+
"files": [
|
|
8
|
+
{
|
|
9
|
+
"path": "SKILL.md",
|
|
10
|
+
"content": "---\nname: software-design\nlabel: \"Software design (deep modules)\"\nsource: https://github.com/mattpocock/skills\ndescription: >\n Shared vocabulary for designing deep modules: interfaces, seams, depth,\n adapters, the deletion test. Use when designing or improving a module's\n interface, deciding where a seam goes, making code more testable, or when\n another skill needs the deep-module language.\n---\n<!-- Adapted from mattpocock/skills (MIT, (c) 2026 Matt Pocock) -->\n\nDesign **deep modules**: a lot of behaviour behind a small interface, placed at a clean seam, testable through that interface. Use this language wherever code is designed or restructured. The aim: leverage for callers, locality for maintainers, testability for everyone.\n\n## Glossary\n\nConsistent language is the point. Prefer these terms over the looser ones noted in parentheses. Avoid vague catch-alls — \"component\", \"service\", \"API\", \"boundary\" — and name a module by what it provides, not by its architectural layer.\n\n- **Module** — anything with an interface and an implementation. Scale-agnostic: a function, class, package, or tier-spanning slice. (Prefer over: unit, component.)\n- **Interface** — everything a caller must know to use the module correctly: the type signature, plus invariants, ordering constraints, error modes, required configuration, performance characteristics. (Prefer over: signature — too narrow, it's only the type-level surface.)\n- **Implementation** — what's inside a module, its body of code. Distinct from **adapter**: a thing can be a small adapter with a large implementation (a Postgres repo) or a large adapter with a small implementation (an in-memory fake). Reach for \"adapter\" when the seam is the topic, \"implementation\" otherwise.\n- **Depth** — leverage at the interface: how much behaviour a caller (or test) can exercise per unit of interface it must learn. **Deep** = large behaviour behind a small interface; **shallow** = the interface is nearly as complex as the implementation.\n- **Seam** _(Michael Feathers)_ — a place where you can alter behaviour without editing in that place; the _location_ where a module's interface lives. Where to put the seam is its own design decision, distinct from what goes behind it. (Prefer over: boundary, which is overloaded with DDD's bounded context.)\n- **Adapter** — a concrete thing that satisfies an interface at a seam. Describes _role_ (which slot it fills), not substance (what's inside).\n- **Leverage** — what callers get from depth: more capability per unit of interface learned. One implementation pays back across N call sites and M tests.\n- **Locality** — what maintainers get from depth: change, bugs, knowledge and verification concentrate in one place instead of spreading across callers. Fix once, fixed everywhere.\n\n## Deep vs shallow\n\n**Deep module** = small interface + lots of implementation:\n\n```\n┌─────────────────────┐\n│ Small interface │ ← few methods, simple params\n├─────────────────────┤\n│ │\n│ Deep implementation │ ← complex logic hidden\n│ │\n└─────────────────────┘\n```\n\n**Shallow module** = large interface + thin implementation (avoid):\n\n```\n┌─────────────────────────────────┐\n│ Large interface │ ← many methods, complex params\n├─────────────────────────────────┤\n│ Thin implementation │ ← just passes through\n└─────────────────────────────────┘\n```\n\nWhen designing an interface, ask: can I reduce the number of methods? simplify the parameters? hide more complexity inside?\n\n## Principles\n\n- **Depth is a property of the interface, not the implementation.** A deep module can be internally composed of small, mockable, swappable parts — they just aren't part of the interface. A module can have **internal seams** (private to its implementation, used by its own tests) as well as the **external seam** at its interface.\n- **The deletion test.** Imagine deleting the module. If complexity vanishes, it was a pass-through. If complexity reappears across N callers, it was earning its keep.\n- **The interface is the test surface.** Callers and tests cross the same seam. Wanting to test _past_ the interface means the module is probably the wrong shape.\n- **One adapter means a hypothetical seam. Two adapters means a real one.** Don't introduce a seam unless something actually varies across it.\n\n## Designing for testability\n\nGood interfaces make testing natural:\n\n1. **Accept dependencies, don't create them.**\n\n ```typescript\n // Testable\n function processOrder(order, paymentGateway) {}\n // Hard to test\n function processOrder(order) {\n const gateway = new StripeGateway();\n }\n ```\n\n2. **Return results, don't produce side effects.**\n\n ```typescript\n // Testable\n function calculateDiscount(cart): Discount {}\n // Hard to test\n function applyDiscount(cart): void {\n cart.total -= discount;\n }\n ```\n\n3. **Small surface area.** Fewer methods = fewer tests. Fewer params = simpler setup.\n\n## Relationships\n\n- A **module** has exactly one **interface** (the surface it presents to callers and tests).\n- **Depth** is a property of a module, measured against its interface.\n- A **seam** is where a module's interface lives.\n- An **adapter** sits at a seam and satisfies the interface.\n- **Depth** produces **leverage** for callers and **locality** for maintainers.\n\n## Rejected framings\n\n- **Depth as ratio of implementation-lines to interface-lines** (Ousterhout): rewards padding the implementation. Use depth-as-leverage instead.\n- **\"Interface\" as the TypeScript `interface` keyword or a class's public methods:** too narrow — interface here includes every fact a caller must know.\n\n## Going deeper\n\n- **Deepening a cluster given its dependencies** — see [DEEPENING.md](DEEPENING.md): dependency categories, seam discipline, replace-don't-layer testing.\n- **Exploring alternative interfaces** — see [DESIGN-IT-TWICE.md](DESIGN-IT-TWICE.md): fan out parallel subagents to design the interface several radically different ways, then compare on depth, locality and seam placement.\n",
|
|
11
|
+
"kind": "skill-md"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"path": "DEEPENING.md",
|
|
15
|
+
"content": "<!-- Adapted from mattpocock/skills (MIT, (c) 2026 Matt Pocock) -->\n# Deepening\n\nHow to deepen a cluster of shallow modules safely, given its dependencies. Assumes the vocabulary in [SKILL.md](SKILL.md) — **module**, **interface**, **seam**, **adapter**.\n\n## Dependency categories\n\nWhen assessing a candidate for deepening, classify its dependencies. The category determines how the deepened module is tested across its seam.\n\n### 1. In-process\n\nPure computation, in-memory state, no I/O. Always deepenable — merge the modules and test through the new interface directly. No adapter needed.\n\n### 2. Local-substitutable\n\nDependencies with local test stand-ins (PGLite for Postgres, in-memory filesystem). Deepenable if the stand-in exists. The deepened module is tested with the stand-in running in the test suite. The seam is internal; no port at the module's external interface.\n\n### 3. Remote but owned (ports & adapters)\n\nYour own services across a network boundary (microservices, internal APIs). Define a **port** (interface) at the seam. The deep module owns the logic; the transport is injected as an **adapter**. Tests use an in-memory adapter; production uses an HTTP/gRPC/queue adapter.\n\nRecommendation shape: _\"Define a port at the seam, implement an HTTP adapter for production and an in-memory adapter for testing, so the logic sits in one deep module even though it's deployed across a network.\"_\n\n### 4. True external (mock)\n\nThird-party services (Stripe, Twilio, etc.) you don't control. The deepened module takes the external dependency as an injected port; tests provide a mock adapter.\n\n## Seam discipline\n\n- **One adapter means a hypothetical seam. Two adapters means a real one.** Don't introduce a port unless at least two adapters are justified (typically production + test). A single-adapter seam is just indirection.\n- **Internal seams vs external seams.** A deep module can have internal seams (private to its implementation, used by its own tests) as well as the external seam at its interface. Don't expose internal seams through the interface just because tests use them.\n\n## Testing strategy: replace, don't layer\n\n- Old unit tests on shallow modules become waste once tests at the deepened module's interface exist — delete them.\n- Write new tests at the deepened module's interface. **The interface is the test surface.**\n- Tests assert on observable outcomes through the interface, not internal state.\n- Tests should survive internal refactors — they describe behaviour, not implementation. A test that has to change when the implementation changes is testing past the interface.\n",
|
|
16
|
+
"kind": "raw"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"path": "DESIGN-IT-TWICE.md",
|
|
20
|
+
"content": "<!-- Adapted from mattpocock/skills (MIT, (c) 2026 Matt Pocock) -->\n# Design It Twice\n\nWhen exploring alternative interfaces for a chosen deepening candidate, fan the work out to parallel subagents. Based on \"Design It Twice\" (Ousterhout) — your first idea is unlikely to be the best.\n\nUses the vocabulary in [SKILL.md](SKILL.md) — **module**, **interface**, **seam**, **adapter**, **leverage**.\n\n## Process\n\n### 1. Frame the problem space\n\nBefore fanning out, write a user-facing explanation of the problem space for the chosen candidate:\n\n- The constraints any new interface must satisfy.\n- The dependencies it relies on, and which category they fall into (see [DEEPENING.md](DEEPENING.md)).\n- A rough illustrative code sketch to ground the constraints — not a proposal, just a way to make the constraints concrete.\n\nShow this to the user, then proceed to step 2. The user reads and thinks while the subagents work in parallel.\n\n### 2. Fan out parallel subagents\n\nSpawn several subagents in parallel (three or more). Each must produce a **radically different** interface for the deepened module.\n\nGive each a separate technical brief (file paths, coupling details, dependency category from [DEEPENING.md](DEEPENING.md), what sits behind the seam). The brief is independent of the user-facing problem-space explanation in step 1. Give each a different design constraint, for example:\n\n- **Minimise the interface** — 1–3 entry points max; maximise leverage per entry point.\n- **Maximise flexibility** — support many use cases and extension.\n- **Optimise for the most common caller** — make the default case trivial.\n- **Ports & adapters** (where cross-seam dependencies apply) — design around injected adapters.\n\nInclude the [SKILL.md](SKILL.md) vocabulary in each brief so every subagent names things consistently.\n\nEach subagent outputs:\n\n1. Interface (types, methods, params — plus invariants, ordering, error modes).\n2. Usage example showing how callers use it.\n3. What the implementation hides behind the seam.\n4. Dependency strategy and adapters (see [DEEPENING.md](DEEPENING.md)).\n5. Trade-offs — where leverage is high, where it's thin.\n\n### 3. Present and compare\n\nPresent designs one at a time so the user can absorb each, then compare in prose. Contrast by **depth** (leverage at the interface), **locality** (where change concentrates) and **seam placement**.\n\nAfter comparing, give your own recommendation: which design is strongest and why. If elements from different designs combine well, propose a hybrid. Be opinionated — the user wants a strong read, not a menu.\n",
|
|
21
|
+
"kind": "raw"
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
"standalone": false,
|
|
25
|
+
"meta": {
|
|
26
|
+
"source": "https://github.com/mattpocock/skills"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"name": "sql-migrations",
|
|
4
|
+
"type": "skill",
|
|
5
|
+
"title": "SQL migration discipline",
|
|
6
|
+
"description": "Database migration discipline. Use when writing or reviewing schema or data migrations, planning zero-downtime expand/contract changes, avoiding lock contention, or testing migrations.",
|
|
7
|
+
"files": [
|
|
8
|
+
{
|
|
9
|
+
"path": "SKILL.md",
|
|
10
|
+
"content": "---\nname: sql-migrations\nlabel: \"SQL migration discipline\"\ndescription: >\n Database migration discipline. Use when writing or reviewing schema or data\n migrations, planning zero-downtime expand/contract changes, avoiding lock\n contention, or testing migrations.\n---\n\nMigrations are deploys to your most stateful system — treat them like code, plan them like surgery.\n\nRelational, Postgres-first guidance; the locking section below is PG-specific (`CREATE INDEX CONCURRENTLY`, `NOT VALID`) — MySQL/SQLite differ, adjust for your engine.\n\n## Ground rules\n\n- Every schema change is a checked-in, ordered migration file; never edit an applied migration — write a new one.\n- One logical change per migration; schema and bulky data backfills in separate steps.\n- Down-migrations are documentation, not a recovery strategy: practice roll-forward.\n- Generated SQL is reviewed SQL — read what the ORM/tool emits before applying.\n\n## Zero-downtime: expand → migrate → contract\n\n1. **Expand**: add the new nullable column/table/index alongside the old.\n2. **Migrate**: deploy code writing both/reading new; backfill in batches (bounded `UPDATE ... LIMIT`, sleep between batches).\n3. **Contract**: once verified, drop old columns/paths in a later release.\n\nNever in one step: rename column, change type in place, add NOT NULL with default on a large hot table.\n\n## Locking awareness (Postgres specifics)\n\n- `CREATE INDEX CONCURRENTLY` (outside transactions) on existing tables.\n- `ALTER TABLE ... ADD COLUMN` without volatile default is cheap; with default it rewrites (pre-PG11).\n- Add constraints as `NOT VALID`, then `VALIDATE CONSTRAINT` separately.\n- Set `lock_timeout`/`statement_timeout` in migration sessions so a blocked DDL fails fast instead of queueing the world behind it.\n\n## Testing & safety\n\n- CI applies all migrations to a scratch DB from zero AND from the previous release's dump.\n- Backfills are idempotent and resumable (track progress, tolerate reruns).\n- Before prod: row-count/size estimate, expected lock level, and a written abort plan.\n",
|
|
11
|
+
"kind": "skill-md"
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"standalone": false
|
|
15
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"name": "tdd",
|
|
4
|
+
"type": "skill",
|
|
5
|
+
"title": "Test-driven development",
|
|
6
|
+
"description": "Test-driven development discipline: the red-green loop, tests at pre-agreed seams, and the anti-patterns that make tests worthless. Use when asked to work test-first, when someone says \"red-green-refactor\", or when a feature or bug clearly warrants tests and you are deciding what and where to test.",
|
|
7
|
+
"files": [
|
|
8
|
+
{
|
|
9
|
+
"path": "SKILL.md",
|
|
10
|
+
"content": "---\nname: tdd\nlabel: \"Test-driven development\"\nsource: https://github.com/mattpocock/skills\ndescription: >\n Test-driven development discipline: the red-green loop, tests at pre-agreed\n seams, and the anti-patterns that make tests worthless. Use when asked to work\n test-first, when someone says \"red-green-refactor\", or when a feature or bug\n clearly warrants tests and you are deciding what and where to test.\n---\n<!-- Adapted from mattpocock/skills (MIT, (c) 2026 Matt Pocock) -->\n\nTDD is the red → green loop. This skill is what makes the loop produce tests worth keeping: what a good test is, where tests go, the anti-patterns, the rules. Every section applies on every cycle — consult before and during the loop, not after.\n\n## What a good test is\n\n- Verifies behavior through public interfaces, never implementation details. Code can change entirely; the test shouldn't.\n- Reads like a specification — \"user can checkout with valid cart\" names the capability that exists.\n- Survives refactors because it doesn't care about internal structure.\n\nSee [tests.md](tests.md) for good/bad examples, [mocking.md](mocking.md) for where mocking is allowed.\n\n## Seams: where tests go\n\nA **seam** is the public boundary you test at: the interface where you observe behavior without reaching inside. Tests live at seams, never against internals.\n\n- **Test only at pre-agreed seams.** Before writing any test, write down the seams under test and confirm them with the user. No test at an unconfirmed seam.\n- You can't test everything — agreeing the seams up front lands effort on the critical paths and complex logic instead of every edge case.\n- Ask: \"What's the public interface, and which seams should we test?\"\n\n## Anti-patterns\n\n- **Implementation-coupled** — mocks internal collaborators, tests private methods, or verifies through a side channel (querying the DB instead of using the interface). Tell: the test breaks when you refactor but behavior hasn't changed.\n- **Tautological** — the assertion recomputes the expected value the way the code does (`expect(add(a, b)).toBe(a + b)`, a hand-derived snapshot, a constant asserted equal to itself), so it passes by construction and can never disagree with the code. Expected values come from an independent source of truth — a known-good literal, a worked example, the spec.\n- **Horizontal slicing** — all tests first, then all implementation. Bulk tests verify _imagined_ behavior: you test the _shape_ of things, the tests go insensitive to real changes, and you commit to test structure before understanding the implementation. Work in **vertical slices** — one test → one implementation → repeat, each test a tracer bullet that responds to what the last cycle taught you.\n\n## Rules of the loop\n\n- **Red before green.** Write the failing test first, then only enough code to pass it. No anticipating future tests, no speculative features.\n- **One slice at a time.** One seam, one test, one minimal implementation per cycle.\n- **Refactoring is not part of the loop.** It belongs to the review stage, not the red → green implementation cycle.\n",
|
|
11
|
+
"kind": "skill-md"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"path": "mocking.md",
|
|
15
|
+
"content": "<!-- Adapted from mattpocock/skills (MIT, (c) 2026 Matt Pocock) -->\n# When to Mock\n\nMock at **system boundaries** only:\n\n- External APIs (payment, email, etc.)\n- Databases (sometimes — prefer a test DB)\n- Time / randomness\n- File system (sometimes)\n\nDon't mock your own classes/modules, internal collaborators, or anything you control.\n\n## Designing for mockability\n\nAt system boundaries, design interfaces that are easy to mock.\n\n**1. Use dependency injection.** Pass external dependencies in rather than creating them internally.\n\n```typescript\n// Easy to mock\nfunction processPayment(order, paymentClient) {\n return paymentClient.charge(order.total);\n}\n\n// Hard to mock\nfunction processPayment(order) {\n const client = new StripeClient(process.env.STRIPE_KEY);\n return client.charge(order.total);\n}\n```\n\n**2. Prefer SDK-style interfaces over generic fetchers.** Specific functions per external operation instead of one generic function with conditional logic.\n\n```typescript\n// GOOD: each function is independently mockable\nconst api = {\n getUser: (id) => fetch(`/users/${id}`),\n getOrders: (userId) => fetch(`/users/${userId}/orders`),\n createOrder: (data) => fetch(\"/orders\", { method: \"POST\", body: data }),\n};\n\n// BAD: mocking requires conditional logic inside the mock\nconst api = {\n fetch: (endpoint, options) => fetch(endpoint, options),\n};\n```\n\nThe SDK approach means each mock returns one specific shape, no conditional logic in test setup, easier to see which endpoints a test exercises, and type safety per endpoint.\n",
|
|
16
|
+
"kind": "raw"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"path": "tests.md",
|
|
20
|
+
"content": "<!-- Adapted from mattpocock/skills (MIT, (c) 2026 Matt Pocock) -->\n# Good and Bad Tests\n\n## Good tests\n\n**Integration-style** — test through real interfaces, not mocks of internal parts.\n\n```typescript\n// GOOD: tests observable behavior\ntest(\"user can checkout with valid cart\", async () => {\n const cart = createCart();\n cart.add(product);\n const result = await checkout(cart, paymentMethod);\n expect(result.status).toBe(\"confirmed\");\n});\n```\n\nCharacteristics:\n\n- Tests behavior users/callers care about\n- Uses public API only\n- Survives internal refactors\n- Describes WHAT, not HOW\n- One logical assertion per test\n\n## Bad tests\n\n**Implementation-detail tests** — coupled to internal structure.\n\n```typescript\n// BAD: tests implementation details\ntest(\"checkout calls paymentService.process\", async () => {\n const mockPayment = jest.mock(paymentService);\n await checkout(cart, payment);\n expect(mockPayment.process).toHaveBeenCalledWith(cart.total);\n});\n```\n\nRed flags: mocking internal collaborators, testing private methods, asserting on call counts/order, test breaks when refactoring without behavior change, test name describes HOW not WHAT, verifying through external means instead of the interface.\n\n```typescript\n// BAD: bypasses the interface to verify\ntest(\"createUser saves to database\", async () => {\n await createUser({ name: \"Alice\" });\n const row = await db.query(\"SELECT * FROM users WHERE name = ?\", [\"Alice\"]);\n expect(row).toBeDefined();\n});\n\n// GOOD: verifies through the interface\ntest(\"createUser makes user retrievable\", async () => {\n const user = await createUser({ name: \"Alice\" });\n const retrieved = await getUser(user.id);\n expect(retrieved.name).toBe(\"Alice\");\n});\n```\n\n**Tautological tests** — expected value restates the implementation, so the test passes by construction.\n\n```typescript\n// BAD: expected value recomputed the way the code computes it\ntest(\"calculateTotal sums line items\", () => {\n const items = [{ price: 10 }, { price: 5 }];\n const expected = items.reduce((sum, i) => sum + i.price, 0);\n expect(calculateTotal(items)).toBe(expected);\n});\n\n// GOOD: expected value is an independent, known literal\ntest(\"calculateTotal sums line items\", () => {\n expect(calculateTotal([{ price: 10 }, { price: 5 }])).toBe(15);\n});\n```\n",
|
|
21
|
+
"kind": "raw"
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
"standalone": false,
|
|
25
|
+
"meta": {
|
|
26
|
+
"source": "https://github.com/mattpocock/skills"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"name": "typescript-dev",
|
|
4
|
+
"type": "skill",
|
|
5
|
+
"title": "TypeScript development",
|
|
6
|
+
"description": "Strict TypeScript development. Use when writing or reviewing any TypeScript code, configuring tsconfig, designing types, or validating data at runtime boundaries.",
|
|
7
|
+
"files": [
|
|
8
|
+
{
|
|
9
|
+
"path": "SKILL.md",
|
|
10
|
+
"content": "---\nname: typescript-dev\nlabel: \"TypeScript development\"\ndependencies: [node]\ndescription: >\n Strict TypeScript development. Use when writing or reviewing any TypeScript\n code, configuring tsconfig, designing types, or validating data at runtime\n boundaries.\n---\n\nTypeScript with the compiler turned all the way up — types are the first test suite.\n\n## Compiler baseline\n\n- `\"strict\": true` plus `noUncheckedIndexedAccess`, `noImplicitOverride`, `exactOptionalPropertyTypes`.\n- `\"type\": \"module\"`, `moduleResolution: \"bundler\"` (or nodenext with explicit extensions).\n- `tsc --noEmit` in CI even when a bundler builds — the bundler does not typecheck.\n\n## Type design\n\n- String-literal unions over enums: `type Status = \"open\" | \"closed\"` + `as const` arrays for runtime lists (single source of truth).\n- `unknown` over `any`; narrow with type guards. `any` only at well-commented interop edges.\n- Discriminated unions + exhaustive `switch` (with `never` check) for state machines and variants.\n- Derive, don't duplicate: `keyof`, `typeof`, `Pick/Omit/Partial`, template literal types.\n- Functions take the narrowest type they need, return the widest they can guarantee.\n\n## Boundaries\n\n- Validate ALL external data at runtime (zod/valibot or hand-written guards): API responses, file contents, env vars. `as` casts on raw IO are bugs waiting.\n- Centralize parsing at the edge; everything behind it works with trusted, typed values.\n- Errors: throw `Error` subclasses or return result unions (`{ ok: true, value } | { ok: false, error }`) — pick one style per codebase and stick to it.\n\n## Hygiene\n\n- No default exports (better refactors/grep); barrel files only at package boundaries.\n- `readonly` fields and `ReadonlyArray` for data that must not mutate.\n- Avoid type assertions in tests too — if the test needs `as`, the API is lying.\n- Lint with typed rules (typescript-eslint or biome); `noUnusedLocals` belongs in tsconfig.\n",
|
|
11
|
+
"kind": "skill-md"
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"standalone": false,
|
|
15
|
+
"meta": {
|
|
16
|
+
"systemDependencies": [
|
|
17
|
+
"node"
|
|
18
|
+
]
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"name": "visual-assets",
|
|
4
|
+
"type": "skill",
|
|
5
|
+
"title": "visual-assets",
|
|
6
|
+
"description": "Visual assets as code — HTML/CSS at exact pixel size, SVG, HTML decks. Use when asked for a banner, social or OG image, ad creative, cover or hero image, slide or pitch deck, logo concept, brand board, icon set, YouTube thumbnail, or email header. Load design-taste alongside as the aesthetic foundation.",
|
|
7
|
+
"dependencies": [
|
|
8
|
+
"skill:design-taste"
|
|
9
|
+
],
|
|
10
|
+
"files": [
|
|
11
|
+
{
|
|
12
|
+
"path": "SKILL.md",
|
|
13
|
+
"content": "---\nname: visual-assets\ndescription: >\n Visual assets as code — HTML/CSS at exact pixel size, SVG, HTML decks. Use\n when asked for a banner, social or OG image, ad creative, cover or hero image,\n slide or pitch deck, logo concept, brand board, icon set, YouTube thumbnail,\n or email header. Load design-taste alongside as the aesthetic foundation.\nrequires: [design-taste]\n---\n\n# Visual Assets\n\nArtifacts as code only: HTML+CSS at exact pixel size (screenshot to PNG), SVG icons and logos,\nHTML brand boards and slide decks. This skill does NOT call image generators. If the user wants\ngenerated imagery (photos, illustrations, AI art), state that plainly and stop. Placeholders:\npicsum.photos/seed/{descriptive-seed}/{w}/{h}. Build at exact platform px, never approximate.\n\n## Size reference\n\n### Banners and covers\n\n| Target | px | Ratio |\n|---|---|---|\n| Facebook cover | 820x312 | ~2.6:1 |\n| Facebook cover mobile | 640x360 | 16:9 |\n| Facebook event | 1920x1080 | 16:9 |\n| X header | 1500x500 | 3:1 |\n| X ad | 800x418 | ~2:1 |\n| LinkedIn company | 1128x191 | ~6:1 |\n| LinkedIn personal | 1584x396 | 4:1 |\n| YouTube channel art | 2560x1440, text inside 1546x423 safe area | 16:9 |\n| Instagram post | 1080x1080 | 1:1 |\n| Instagram story/reel | 1080x1920 | 9:16 |\n| Pinterest pin | 1000x1500 | 2:3 |\n\n### Display ads (Google Display Network)\n\n| Unit | px | Note |\n|---|---|---|\n| Medium Rectangle | 300x250 | highest CTR |\n| Large Rectangle | 336x280 | high performer |\n| Leaderboard | 728x90 | top of page |\n| Billboard | 970x250 | desktop hero |\n| Half Page | 300x600 | premium |\n| Wide Skyscraper | 160x600 | sidebar |\n| Mobile | 320x50 | mobile default |\n| Large Mobile | 320x100 | mobile hero |\n\n### Posts, web, email\n\n| Target | px |\n|---|---|\n| Web hero | 1920x600 to 1920x1080 |\n| Web section banner | 1200x400 |\n| Blog / OG header | 1200x628 |\n| Email header | 600x200 |\n| Facebook post | 1200x630 |\n| X post | 1200x675 (16:9), card 800x418 |\n| LinkedIn post | 1200x627, article 1200x644 |\n| Instagram carousel | 1080x1350 (4:5) |\n| YouTube thumbnail | 1280x720 |\n| TikTok cover | 1080x1920 |\n| Threads | 1080x1080 |\n\nPrint: roll-up 850x2000mm, step-and-repeat 8x8ft, outdoor vinyl 6x3ft, trade show 33x78in.\nAlways 300 DPI (150 for large format), 3-5mm bleed, CMYK color space.\nAspect guidance: snap to 1:1, 4:5, 9:16, 16:9, 3:1, 2:3. Platform unknown: ask, else 16:9 / 1:1.\n\n## Banner rules\n\n- 3-zone hierarchy: top = logo + value proposition, middle = support copy + visual, bottom = CTA.\n- Safe zone: content in central 70-80%; no text or CTA within 50-100px of any edge; Meta/IG keep\n central 80% (UI chrome); YouTube text inside 1546x423.\n- ONE CTA per banner: high contrast, bottom-right, min 44px height, action verb (Get / Start / Download / Claim).\n- Type: max 2 typefaces, body >=16px, headline >=32px digital, contrast >=4.5:1, max 7 words per line, max 3 lines on ads.\n- Text ratio: ads <20% text coverage (Meta penalizes), social covers 60/40 image:text, print\n headlines 70pt+ for 3-5m viewing (1pt per foot of distance).\n\nStyle taxonomy, offer 2-3 complementary options per brief:\nMinimalist (SaaS/tech; white space, single focal point, 1-2 colors); Bold Typography\n(announcements; type IS the design); Gradient/Color Wash (modern brands; mesh blends);\nPhoto-Based (lifestyle/ecommerce; full-bleed photo + overlay); Illustrated/Hand-Drawn (artisan,\nbespoke); Geometric/Abstract (tech/fintech; shapes, grids); Retro/Vintage (food/beverage, craft;\nhalftone, muted); Glassmorphism (SaaS/apps; frosted panels, blur); 3D/Sculptural (product/tech;\nrendered depth); Neon/Cyberpunk (gaming/events; dark bg, glow); Duotone (two-color photo\ntreatment); Editorial/Magazine (media/luxury; grid, pull quotes); Collage/Mixed Media (layered\ncutouts); Retro Futurism (chrome, space-age); Expressive/Anti-Design (deliberate rule-breaking);\nDigi-Cute/Kawaii (youth; pastel, pixel); Tactile/Sensory (puffy hyper-real); Data/Infographic\n(stats as heroes); Dark Mode/Moody (near-black, jewel tones); Flat/Solid (single bg color, clean\nicons, no gradients); Nature/Organic (earthy, sustainable); Motion-Ready/Kinetic (layered, loopable).\n\n## HTML artifact workflow (banners, social images, boards)\n\n1. Exact-px viewport: html,body fixed to WxH px, overflow hidden, absolutely positioned layers inside.\n2. Self-contained single file: inline CSS; fonts only via Google Fonts link.\n3. No scrolling ever. One focal point, clear eye flow.\n4. Min type at 1080px width, scale proportionally for other widths:\n\n| Headline | Subhead | Body | Caption | CTA |\n|---|---|---|---|---|\n| 48px bold/black | 32px semibold | 24px regular | 18px | 28px bold |\n\n5. Test at 50% zoom (feed thumbnail legibility) and 100%.\n6. Screenshot export, always 3-5s delay so webfonts settle:\n\n```bash\nchrome --headless --disable-gpu --no-sandbox --hide-scrollbars \\\n --window-size=WxH --virtual-time-budget=5000 --screenshot=out.png file.html\n```\n\n Playwright alternative: viewport exact WxH with deviceScaleFactor 2 (retina), goto waitUntil\n networkidle, waitForTimeout(3000-5000), then screenshot.\n7. Naming: assets/banners/{campaign}/{style}-{w}x{h}.png, kebab-case, YYMMDD- prefix when time-sensitive.\n8. Verify PNG: fonts rendered (no system fallback), no clipping, safe zone held, contrast AA. Fix, re-export, repeat.\n\n## Slide decks (HTML)\n\nHTML slide decks (screenshot-ready, browser-rendered) belong to this skill; native `.pptx` files use the pptx-create skill.\n\nVisual identity per deck comes from brand tokens or a design-search pairing/palette chosen for\nthe brief. Two decks from different briefs must not look like the same template. This section is\nSTRUCTURAL ONLY: letterbox lock, slide mechanics, overflow guard, progress/nav JS, responsive\nclamps are fixed; every color, gradient, and font is sourced from tokens or design-search, never\nhardcoded.\n\n16:9 letterbox lock, deck keeps ratio on any desktop screen:\n\n```css\n.slide-deck{width:100vw;height:100vh;width:100dvw;height:100dvh;position:relative}\n@media(min-width:769px){.slide-deck{max-width:calc(100dvh*16/9);\n max-height:calc(100dvw*9/16);position:absolute;inset:0;margin:auto}}\n```\n\nAnatomy (structure fixed; identity from tokens/design-search):\n- body: overflow hidden, background var(--color-background); headings var(--typography-font-heading), body var(--typography-font-body). When no tokens, pick a pairing from design-search --domain typography, not a stock fallback.\n- .slide: absolute 100%, flex center, padding 60px, opacity 0 + visibility hidden, .active visible, transition opacity .4s, overflow hidden.\n- .slide-content wrapper MANDATORY overflow guard: max 100%, overflow hidden, flex column center, gap 16px.\n- .slide-title: clamp(32px,6vw,80px), line-height 1.1; color var(--color-foreground) by default, or a brand display treatment chosen per brief. A gradient title is allowed ONLY if it passes design-taste (tonal, low-chroma, same-hue, never the purple-blue AI gradient) and uses brand token stops via background-clip:text.\n- Progress bar fixed top 3px, width % via JS, background var(--color-primary). Nav fixed bottom 30px centered, 40px circle buttons from a token surface (e.g. var(--color-muted) or a low-alpha surface tint), counter from a muted token color (e.g. var(--color-muted-foreground)) 14px.\n- JS essentials: showSlide(n) clamps 1..total, toggles .active, updates counter + progress; ArrowRight/Space next (preventDefault), ArrowLeft prev; click anywhere except .nav-controls advances.\n\nResponsive: <=768px padding 32/24, title clamp(28px,5vw,48px), h2 clamp(20px,4vw,32px), body\nclamp(14px,2.5vw,18px); <=480px padding 24/16, title clamp(22px,6vw,36px), h2\nclamp(18px,4.5vw,28px), body clamp(12px,3vw,16px), nav bottom 16px, buttons 32px.\n\nCharts: Chart.js CDN 4.4.1 umd, never CSS-hacked bars. Container width min(80%,600px), height\nclamp(200px,40vh,350px). Options: responsive true, maintainAspectRatio false, legend off. Colors\nfrom tokens: dataset borderColor var(--color-primary), backgroundColor primary at ~10% alpha,\nborderWidth 3, fill true, tension .4; grid + ticks from muted tokens (var(--color-border),\nvar(--color-muted-foreground)). Hardcoded dark-theme values (grid rgba(255,255,255,.05), ticks\n#B8B8D0, borderColor #FF6B6B) are an example only; use project tokens, not these literals.\n\n### Goal to layout (BREAK = pattern-break candidate, BG = background image)\n\n| Goal | Emotion | Layout | Direction | Weight | Flags |\n|---|---|---|---|---|---|\n| hook | curiosity | split-hero | visual-right | 70-visual | BG |\n| problem | frustration | card-grid | centered | balanced | |\n| agitation | fear | full-bleed-stat | centered | 100-text | BREAK |\n| solution | relief | split-feature | visual-left | 50-50 | BG |\n| proof | trust | metric-grid | centered | numbers-dominant | |\n| social | connection | quote-hero | centered | 80-text | BREAK BG |\n| comparison | evaluation | split-compare | side-by-side | balanced | |\n| traction | confidence | chart-insight | chart-left | 60-chart | |\n| cta | urgency | high-contrast-cta | centered | 100-text | BREAK BG |\n| team | warmth | team-grid | centered | balanced | BG |\n| pricing | evaluation | pricing-cards | centered | balanced | |\n| demo | interest | split-demo | visual-left | 60-visual | |\n| vision | hope | full-bleed-hero | centered | 100-visual | BREAK BG |\n| timeline | narrative | timeline-flow | horizontal | balanced | |\n| features | clarity | feature-grid | centered | balanced | |\n\nPattern-break rule: at 1/3 and 2/3 of the deck, break the visual pattern (full-bleed, 100-text\nstat, high-contrast CTA) to reset attention. Duarte sparkline: alternate What-Is (frustration) and\nWhat-Could-Be (hope). Any gradient must pass design-taste (tonal, low-chroma, single-hue; no\npurple-blue AI gradient); gradient is never a required treatment.\n\n### Typography scale per slide type (primary/secondary/accent px)\n\n| Slide type | Sizes | Weights | Tracking | Line height |\n|---|---|---|---|---|\n| hero-statement | 120/32/14 | 700/400 | tight | 1.0 |\n| title-only | 80/24/14 | 700/400 | tight | 1.0 |\n| subtitle-heavy | 56/28/16 | 600/400 | normal | 1.2 |\n| metric-callout | 96/18/12 | 700/500 | normal | 1.1 |\n| data-insight | 48/20/14 | 700/400 | normal | 1.2 |\n| cta-action | 64/24/16 | 700/500 | tight | 1.1 |\n| feature-grid | 28/16/12 | 600/400 | normal | 1.4 |\n| body-focus | 24/18/14 | 500/400 | normal | 1.6 |\n| quote-block | 36/18/14 | 400 italic | loose | 1.5 |\n| testimonial | 32/20/14 | 400 italic | loose | 1.5 |\n| comparison | 32/16/12 | 600/400 | normal | 1.3 |\n| timeline | 28/16/12 | 500/400 | normal | 1.4 |\n| pricing | 48/20/14 | 700/500 | normal | 1.2 |\n| team | 24/16/14 | 600/400 | normal | 1.4 |\n\n### Emotion to surface mapping (one optional dark-theme example)\n\nThis is ONE optional dark-theme mapping, not a default. Derive an equivalent from the project's\nbrand tokens; do not default every deck to this theme. \"gradient\" / \"gradient-text\" cells are\nallowed only when they pass design-taste (tonal, low-chroma, single-hue; no purple-blue AI\ngradient); otherwise use a solid brand surface. Two decks from different brands must not share\nthis palette.\n\n| Emotion | Background | Text | Accent usage | Extras |\n|---|---|---|---|---|\n| frustration | dark-surface | foreground | minimal | subtle-border cards |\n| hope | accent-bleed | dark | none | full-bleed |\n| fear | dark-background | primary | stats-only | glow-primary cards |\n| relief | surface | foreground | icons | accent-bar cards |\n| trust | surface-elevated | foreground | metrics | subtle-border cards |\n| urgency | primary-surface | contrast-fg | cta-button | full-bleed (tonal gradient optional, design-taste-gated) |\n| curiosity | dark-glow | foreground/display | badge | glow-secondary cards |\n| confidence | surface | foreground | chart-accent | |\n| warmth | dark-surface | foreground | avatar-ring | |\n| evaluation | surface-elevated | foreground | highlight | comparison cards |\n| narrative | dark-background | foreground-secondary | timeline-dots | |\n| clarity | surface | foreground | icons | feature-card |\n| interest | dark-glow | foreground | demo-highlight | glow |\n\nLayout to animation: Title fade-up; Problem stagger; Solution scale-in; Feature Grid stagger;\nMetrics stagger-scale; Comparison fade-up; Timeline stagger; Team stagger; Quote fade-up;\nTwo-Column fade-up; Big Number count-up; Screenshot scale-in; Pricing stagger; CTA pulse.\nTimings: fadeUp .6s from translateY(30px); scaleIn .5s from scale(.9); count 1s; stagger child delays .1/.2/.3/.4s.\n\n## Copy formulas\n\n- PAS (problem slides): \"[Pain]? Every [timeframe], [consequence]. [Solution] fixes this.\"\n- AIDA (CTA/closing): \"[Bold statement]. [Benefit]. [Social proof]. [CTA].\"\n- FAB (features): \"[Feature] lets you [advantage], so you can [benefit].\"\n- Cost of Inaction (urgency): \"Without [solution], you're losing [amount] every [timeframe].\"\n- Before-After-Bridge (transformation): \"[Pain before]. [Desired after]. [Solution] is the bridge.\"\n\nSlide type to formula + emotion: Title = AIDA/Hook, curiosity; Problem = PAS, frustration;\nCost/Risk = Cost of Inaction, fear; Solution = FAB/BAB, hope; Features = FAB, confidence;\nTraction = Proof Stack, trust; Social Proof = Testimonial, trust; Pricing = Value Stack,\nconfidence; CTA = AIDA/Urgency, urgency.\n\nHeadline patterns:\n- Power: \"Stop [bad]\", \"Get [result] in [timeframe]\", \"The [adjective] way to [action]\", \"Why [audience] choose [product]\", \"[N] ways to [goal]\".\n- Contrast: \"[Old way] is dead. Meet [new].\", \"Don't [bad]. Instead, [good].\", \"From [pain] to [benefit].\"\n- Social proof: \"[N]+ [users] trust [product]\", \"Join [co] and [co]\", \"As seen in [publication]\".\n\nNeed to formula: urgency = CoI/Scarcity; trust = Social Proof/Testimonial; value = FAB/Value\nStack; action = AIDA/CTA; story = BAB/Story Arc; data = Proof Stack.\n\n## Deck strategies\n\n| Strategy | Slides | Audience |\n|---|---|---|\n| YC Seed | 10-12 | seed VCs |\n| Guy Kawasaki 10/20/30 | 10 | investors, 20-min pitch |\n| Series A | 12-15 | growth VCs |\n| Product Demo | 5-8 | prospects |\n| Sales Pitch | 7-10 | qualified leads |\n| Duarte Sparkline | varies | keynote audiences |\n| Problem-Solution-Benefit | 3-5 | time-pressed execs |\n| QBR | 10-15 | leadership |\n| All-Hands | 8-12 | employees |\n| Conference Talk | 15-25 | attendees |\n| Workshop | 20-40 | trainees |\n| Case Study | 8-12 | prospects |\n| Competitive Analysis | 6-10 | internal |\n| Board Meeting | 15-20 | directors |\n| Webinar | 20-30 | leads |\n\nYC 10: Title/Hook, Problem, Solution, Traction, Market, Product, Business Model, Team,\nFinancials, Ask. Arc: curiosity, frustration, hope, confidence, trust, urgency.\nSales 9: Personalized Hook, Their Problem, Cost of Inaction, Solution, Proof/Cases,\nDifferentiators, Pricing/ROI, Objection Handling, CTA + Next Steps. Arc: connection,\nfrustration, fear, hope, trust, confidence, urgency.\nDemo 6: Hook/Problem, Solution Overview, Live Demo/Screens, Key Features, Benefits/Pricing,\nCTA. Arc: curiosity, frustration, hope, confidence, urgency.\n\nPicker: raising money = YC/Series A/Kawasaki; selling = Sales/Demo; internal =\nQBR/All-Hands/Board; speaking = Conference/Workshop; proving = Case Study/Competitive Analysis;\nlead gen = Webinar.\n\n## Logo concepts and brand boards (SVG/HTML)\n\n| Logo type | Best for | Example |\n|---|---|---|\n| Wordmark | established, memorable name | Google |\n| Lettermark | long names, 2-4 letters | IBM, NASA |\n| Pictorial | brands with existing equity | Apple |\n| Abstract | tech, differentiation | Airbnb |\n| Mascot | family, sports, food | KFC |\n| Emblem | traditional; scales poorly | Starbucks |\n| Combination | new brands, most versatile | Burger King |\n\nSelection: tech startup = Minimalist/Abstract (+Geometric/Gradient); law firm = Wordmark/Emblem\n(+Lettermark); restaurant = Mascot/Badge (+Vintage/Combination); fashion = Wordmark/Luxury\n(+Monogram/Line Art); healthcare = Professional/Line Art (+Abstract/Combination); nonprofit =\nCombination/Emblem (+Organic/Hand-Drawn).\n\n| Color | Signal | Industries | Hexes |\n|---|---|---|---|\n| Blue | trust | finance, tech, healthcare | #003366 #0055A4 #0EA5E9 |\n| Red | energy | food, sports, entertainment; CAUTION healthcare | #DC2626 #EF4444 #9F1239 |\n| Green | growth | eco, wellness | #228B22 #2E8B57 #10B981 |\n| Gold | luxury, optimism | fashion, jewelry, hotels | #D4AF37 #F59E0B #FACC15 |\n| Purple | creative | beauty, tech | #7C3AED #A78BFA #581C87 |\n\nIndustry avoid: tech brown/beige; healthcare red/black; finance bright neon; food blue\n(appetite suppressant); fashion neon; eco neon/black; children dark/muted.\n\nScalability checklist: recognizable at 16px favicon; works in a single color; clear in black\nand white; readable at business-card size; no details that vanish when small.\n\nUsage rules: clear space = height of the logo mark on all sides; min digital sizes full logo\n120px wide, icon 24px (32px in UI). Don'ts: stretch, rotate, drop shadow, gradient fill,\nrecolor, add outline, busy background, crop, rearrange, add elements.\n\n### Brand boards (HTML)\n\nBoard = visual argument: what the brand represents, core metaphor, how the logo expresses it,\nhow the system scales, why it is ownable. Default 3x3 grid board, dark charcoal canvas, strong\ngutters, large negative space.\n\nCategory to symbol: devtool = cursor/frame/bolt/scaffold/grid; AI assistant =\nspark/orbit/signal/path/node; security = shield/eye/seal/protected core; gaming =\ndice/gem/card/trophy; voice AI = waveform/mic/orb/speech path; compliance =\nseal/badge/document/shield; drones/robotics = wing/owl/crosshair/path/zone; luxury/editorial =\nmonogram/seal/paper/emboss; productivity = path/check/block/calendar/light. Never random symbols.\n\nLogo concept methods, use 1, combine max 2: Monogram+Meaning (initial fused with metaphor via\nnegative space or geometry); Product Action (build = frame/scaffold, protect = shield, convert\n= arrow, speak = waveform); Metaphor Fusion (owl+drone, shield+mountain); Negative Space\n(hidden arrow, cutout initial); Construction Geometry (circles, grids, modular blocks; one\npanel may show construction).\n\nBoard rhythm: not every panel loud; sequence quiet, functional, emotional, technical,\natmospheric, detailed. Text sparse: brand name, 1 tagline, 1 URL, 2-5 section labels. Never\nparagraphs, lorem, or tiny fake body copy.\n\n## SVG icons\n\nRules: viewBox=\"0 0 24 24\"; stroke/fill currentColor for CSS inheritance; always a <title> for\na11y; minimal path nodes; no embedded fonts or raster images; stroke-linecap and\nstroke-linejoin round for outlined styles; design at 24px, test at 16px and 48px; ONE family\nper project, fixed stroke width.\n\n| Style | Stroke/Fill | Use |\n|---|---|---|\n| outlined | 2px / none | web UI, dashboards |\n| filled | 0 / solid | mobile nav |\n| duotone | 0 / dual, secondary 30% opacity | marketing |\n| thin | 1-1.5px / none | luxury, editorial |\n| bold | 3px / none | headers, hero |\n| rounded | 2px, round caps | friendly, health |\n| sharp | 2px, mitered | tech, fintech, enterprise |\n| flat | 0 / solid | Material style |\n| gradient | 0 / gradient fill | modern SaaS |\n| glassmorphism | 1px / semi-transparent | overlays |\n| pixel | 0 / solid | gaming, retro |\n| hand-drawn | varies | artisan |\n| isometric | 1-2px / partial, 30deg angles | tech docs |\n| glyph | 0 / solid | system UI |\n| animated-ready | 2px + named groups/IDs | CSS/JS animation targets |\n\n## Design tokens\n\nIf the project ships assets/design-tokens.css (or design-tokens.css anywhere in the repo),\nimport it and consume var(--color-primary), var(--color-background),\nvar(--typography-font-heading), var(--primitive-gradient-primary) instead of raw values. When\ntokens exist they are MANDATORY for decks and banners: no hardcoded hex/rgb/hsl/font-family.\nWhen no token file exists, source identity from design-search (--domain color / typography) per\nbrief, not stock fallbacks. This governs the Slide decks section above: every deck color, gradient,\nand font resolves to a token or a design-search choice. Run the token-validate tool on outputs to\ncheck compliance before delivery.\n",
|
|
14
|
+
"kind": "skill-md"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"name": "wayfinder",
|
|
4
|
+
"type": "skill",
|
|
5
|
+
"title": "Wayfinder (multi-session planning)",
|
|
6
|
+
"description": "Plan a chunk of work too big for one agent session as a shared map of decision tickets, resolving them one at a time until the way to the goal is clear. Use for large, foggy efforts that need multi-session planning.",
|
|
7
|
+
"files": [
|
|
8
|
+
{
|
|
9
|
+
"path": "SKILL.md",
|
|
10
|
+
"content": "---\nname: wayfinder\nlabel: \"Wayfinder (multi-session planning)\"\nsource: https://github.com/mattpocock/skills\ndescription: >\n Plan a chunk of work too big for one agent session as a shared map of\n decision tickets, resolving them one at a time until the way to the goal is\n clear. Use for large, foggy efforts that need multi-session planning.\n---\n\n<!-- Adapted from mattpocock/skills (MIT, (c) 2026 Matt Pocock) -->\n\n# Wayfinder\n\nA loose idea too big for one session, wrapped in fog: the way from here to the\n**destination** is not yet visible. Wayfinding finds that way — charts it as a\n**map** of **decision tickets** (questions whose resolution is a *decision*,\nnot a slice of build), then works them one at a time until the route is clear.\n\n**Plan, don't do.** Each ticket resolves a decision; the map is done when\nnothing is left to decide before someone goes and builds. The pull to just do\nthe work is the signal you have reached the edge of the map — hand off.\n\n## The map\n\nOne canonical artifact (an issue, or a markdown file — whatever the repo\ntracks work with). It is an **index**, not a store: a decision lives in exactly\none place, its ticket; the map only gists and links. Body sections:\n\n- **Destination** — what reaching the end looks like (spec, decision, or\n in-place change). One or two lines; every session orients to it first.\n- **Notes** — domain, skills to consult, standing preferences.\n- **Decisions so far** — one line per resolved ticket: gist plus link.\n- **Not yet specified** — the fog: in-scope questions you can tell are coming\n but cannot yet phrase sharply. Graduates into tickets as the frontier\n advances.\n- **Out of scope** — work consciously ruled beyond the destination. Never\n graduates.\n\nRefer to every ticket **by name**, never a bare id — a wall of `#42, #43` is\nillegible.\n\n## Tickets\n\nEach ticket is one question sized to a single session. **Fog or ticket?** — can\nyou state the question precisely *now* (not answer it)? Sharp → ticket, even if\nblocked. Not sharp → leave in **Not yet specified**; don't pre-slice fog.\n\nThe **frontier** is the open, unblocked, unclaimed tickets — the takeable edge.\nClaim a ticket before working it so concurrent sessions skip it. Most tickets\nresolve through conversation — run `grilling` and `domain-modeling`, one\nquestion at a time; a human-in-the-loop ticket never resolves by the agent\nanswering its own questions.\n\n## The loop\n\n**Chart** (from a loose idea): name the destination first (grill +\ndomain-modeling), then map the frontier breadth-first. No fog surfaced → no map\nneeded, the job fits one session. Otherwise create the map and the tickets you\ncan specify now, wire blocking, leave the rest as fog. Charting is one\nsession's work — resolve nothing.\n\n**Work through** (given a map): load the low-res map, pick the next frontier\nticket (or the one named), claim it, resolve it. Record the answer, close the\nticket, append a line to Decisions-so-far. Then graduate any fog the answer\nmade specifiable, and rule out-of-scope anything now past the destination.\n**Never resolve more than one ticket per session** (research tickets excepted).\n",
|
|
11
|
+
"kind": "skill-md"
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"standalone": false,
|
|
15
|
+
"meta": {
|
|
16
|
+
"source": "https://github.com/mattpocock/skills"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"name": "xlsx-create",
|
|
4
|
+
"type": "skill",
|
|
5
|
+
"title": "XLSX creation",
|
|
6
|
+
"description": "Creating and editing Excel spreadsheets with exceljs on Bun: multi-sheet workbooks, live formulas, number formatting, styling/color-coding, and a formula-recalculation QA loop. Use whenever asked to produce, generate, or edit an .xlsx / .csv spreadsheet or a financial model.",
|
|
7
|
+
"files": [
|
|
8
|
+
{
|
|
9
|
+
"path": "SKILL.md",
|
|
10
|
+
"content": "---\nname: xlsx-create\nlabel: \"XLSX creation\"\ndependencies: [bun]\nsource: https://github.com/anthropics/skills/tree/main/skills/xlsx\ndescription: >\n Creating and editing Excel spreadsheets with exceljs on Bun: multi-sheet\n workbooks, live formulas, number formatting, styling/color-coding, and a\n formula-recalculation QA loop. Use whenever asked to produce, generate, or\n edit an .xlsx / .csv spreadsheet or a financial model.\n---\n\n# XLSX creation (exceljs)\n\nGenerate spreadsheets from code — reproducible scripts, no GUI tools.\n\n## Tool choice\n\n- **Formulas + formatting** (models, styled reports, multi-sheet): write a\n script with [`exceljs`](https://github.com/exceljs/exceljs) and run it with\n `bun --install=fallback script.ts` — Bun auto-resolves the import.\n- **Bulk data / analysis**: for plain tabular dumps a CSV or\n `pandas`/`openpyxl` in Python is fine; reach for exceljs when formulas or\n styling matter.\n- Python alternative if the JS toolchain is unavailable: `openpyxl` for\n formulas/formatting, `pandas` for data analysis.\n\n## exceljs basics\n\n```ts\nimport ExcelJS from \"exceljs\"\n\nconst wb = new ExcelJS.Workbook()\nconst ws = wb.addWorksheet(\"Model\")\n\nws.addRow([\"Quarter\", \"Revenue ($mm)\"])\nws.addRow([\"Q1\", 100])\nws.addRow([\"Q2\", 120])\nws.getCell(\"B4\").value = { formula: \"SUM(B2:B3)\" } // live formula, not a Python-computed literal\n\nws.getRow(1).font = { bold: true, name: \"Arial\" }\nws.getCell(\"B2\").numFmt = \"$#,##0;($#,##0);-\" // negatives in parens, zeros as \"-\"\nws.getColumn(2).width = 16\n\nawait wb.xlsx.writeFile(\"model.xlsx\")\n```\n\n- **Always emit live formulas**, never hardcode a Python/JS-computed result —\n `{ formula: \"...\" }` keeps the sheet recalculable. Same for totals, growth,\n ratios, averages.\n- Cross-sheet reference: `{ formula: \"Assumptions!B5\" }`.\n- Put assumptions (growth, margins) in their own cells and reference them\n (`=B5*(1+$B$6)`), not inline literals.\n\n## Formatting & number formats\n\n- **Font**: consistent professional face (Arial) unless the user says otherwise.\n- **Number formats** via `cell.numFmt`: currency `\"$#,##0\"` (state units in the\n header), percentages `\"0.0%\"`, multiples `\"0.0x\"`, years as text (`\"2024\"` not\n `2,024`), negatives in parentheses.\n- **Financial-model color coding** (`cell.font.color = { argb: \"FF0000FF\" }`):\n blue = hardcoded inputs, black = formulas, green = same-workbook links, red =\n external links; yellow fill = key assumptions to review.\n- Editing an existing file: load with `wb.xlsx.readFile`, and **match the\n existing template's** format/conventions exactly — they override these\n defaults.\n\n## Gotchas\n\n- exceljs writes formulas as strings with **no cached value** — a fresh file\n shows blanks until a real engine recalculates (see QA).\n- ARGB colors are 8-digit (`\"FF0000FF\"` = opaque blue); the leading `FF` is\n alpha, not part of the RGB.\n- Reading back a formula cell gives `{ formula, result }` — `result` is only\n populated after Excel/LibreOffice has recalculated.\n\n## QA (always)\n\nEvery model ships with **zero formula errors** (`#REF!`, `#DIV/0!`, `#VALUE!`,\n`#N/A`, `#NAME?`).\n\n- Recalculate before trusting values — exceljs does not evaluate formulas.\n If LibreOffice is present:\n `soffice --headless --calc --convert-to xlsx --outdir out model.xlsx`\n (or the upstream `recalc.py`) forces recalculation and surfaces errors.\n- Reopen and scan every sheet for the error strings above; fix references,\n denominators (guard `#DIV/0!`), and cross-sheet formats, then recalc again.\n- Spot-check 2-3 sample formula results against hand calcs before building out\n the full model; watch 1-indexed rows and off-by-one ranges.\n",
|
|
11
|
+
"kind": "skill-md"
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"meta": {
|
|
15
|
+
"systemDependencies": [
|
|
16
|
+
"bun"
|
|
17
|
+
],
|
|
18
|
+
"source": "https://github.com/anthropics/skills/tree/main/skills/xlsx"
|
|
19
|
+
}
|
|
20
|
+
}
|