By mateonunez
Enforces a strict TypeScript monorepo architecture with Result types, vertical slices, Biome tooling, node:test, and Fastify patterns. Scaffolds projects, reviews diffs, generates commits, triages issues, and audits accessibility — all governed by a skill-based agent workflow.
Scaffold the per-repo conventions my other engineering skills assume — pnpm + corepack, Biome (1.9 legacy or 2.x new), node:test posture, CONTEXT.md, docs/adr/. Run once per repo before using result-not-throw, vertical-slices, node-native-tests, or single-tool-per-job. Use when user says "setup mateonunez skills", "scaffold conventions", "wire up my skills", or invokes /setup-mateonunez-skills.
I return Result<T, E extends Error> from business logic — never throw. Errors are typed Error subclasses with a code field (AItError pattern). Throws are reserved for boundary code (Fastify handlers, CLI entry, framework adapters). Use when writing TypeScript service/domain functions, when reviewing code that throws inside happy paths, when the codebase already exposes ok()/err() helpers, or when user says "Result type", "don't throw", or "no exceptions".
When data crosses a system boundary into my code, I normalise it into a typed entity with a __type discriminator and a fixed common shape. The vendor's wire format is not my domain model. Use when ingesting external API data, when adding a new connector, when proposing entity types, or when user mentions "normalize", "entity", "ETL", "__type", or "mapper".
I organise code by feature, not by layer. In monorepos, every feature is a workspace package; new files live with the feature they belong to, not in a shared utils/ pile. Use when adding a new feature, deciding where a file goes, proposing package structure, or when user says "vertical slice", "package by feature", or "where should this go".
I use node:test + borp + c8, not Jest or Vitest. The runtime ships a test runner — I use it. Use when adding tests, when an agent reaches for Jest/Vitest, when configuring coverage, or when user says "add a test", "test runner", or "borp".
Own this plugin?
Verify ownership to unlock analytics, metadata editing, and a verified badge. GitHub access is read-only (username + org membership).
Sign in to claimOwn this plugin?
Verify ownership to unlock analytics, metadata editing, and a verified badge. GitHub access is read-only (username + org membership).
Sign in to claimBased on adoption, maintenance, documentation, and repository signals. Not a security audit or endorsement.
Shipping AIt. Music on; nonsense off.
My agent skills — small, composable, behaviour-focused. Each one addresses a real failure mode I've watched coding agents hit, and steers the agent away from it before the failure happens. Organised the way Matt Pocock organises his.
These are not tool docs. They're behaviour interventions in my voice, encoding the way I work — Result<T, E> over throws, vertical slices over layers, Biome over the ESLint+Prettier stack, node:test over Jest. Forged on real projects: ait (a personal AI platform), mateonunez.co (Next.js 16 + WCAG 2.1 AA), and a fistful of Fastify plugins.
If it doesn't hold up in production, it doesn't make the cut.
npx skills add mateonunez/skills
or
git clone https://github.com/mateonunez/skills.git
cd agentfiles
./scripts/link-skills.sh
The script symlinks every SKILL.md under skills/ (excluding deprecated/) into ~/.claude/skills/, where Claude Code picks them up.
I built these for the failure modes I see most often when collaborating with coding agents.
"Errors are values."
— Rob Pike
The problem: agents reflexively throw new Error() in service-layer code, then bury try/catch three layers up at the call site. Control flow becomes invisible. The type system can't help me — every function lies about what it can fail with.
The fix: /result-not-throw. Business logic returns Result<T, E> with discriminated __type errors. Throws are reserved for boundaries (HTTP handlers, CLI entry, framework adapters). The compiler enforces exhaustive error handling.
"The standard library is the first thing you should reach for."
— common sense, often ignored
The problem: every greenfield package gets jest, @types/jest, ts-jest, babel-jest by default. Half a megabyte of dependencies for what node:test ships built into the runtime. Same story with ESLint + Prettier when Biome covers both.
The fix: /node-native-tests and /single-tool-per-job. Use the runtime. Use the one tool that does the job. New dev dependencies have to clear a real bar.
"The best modules are deep. They allow a lot of functionality to be accessed through a simple interface."
— John Ousterhout, A Philosophy of Software Design
The problem: controllers/ here, services/ there, repositories/ over there. Every feature change touches five folders. The horizontal cuts ripple across the codebase on every PR.
The fix: /vertical-slices. Package by feature. The seam between features is a workspace package boundary, not a layer convention. Workspace protocol (workspace:*) and scoped packages (@scope/feature) make the boundary visible at every import site.
"The vendor's wire format is not my domain model."
— every ETL pipeline that ever survived a vendor breaking change
The problem: fetch('https://api.spotify.com/...').then(r => r.json()) and the response goes straight to the database. Three vendors later, every consumer special-cases every shape, and a Spotify API change cascades through six files.
The fix: /entity-normalization. At the boundary, normalise to a typed NormalizedEntity with a __type discriminator. Vendor noise lives in metadata. Downstream code is vendor-agnostic by construction.
"Accessibility is a baseline, not a feature."
— most of the web, getting it wrong
The problem: <div onClick> in place of <button>. Missing alt. outline: none with no replacement. Modals that don't trap focus. The agent ships UI that works for sighted, mouse-using users — and silently breaks for everyone else.
The fix: /a11y-default-review. A short checklist run after every UI change. Keyboard, focus, semantics, ARIA polish. The bar is WCAG 2.1 AA — the same bar I hold mateonunez.co to.
Skills I use daily for code work.
npx claudepluginhub mateonunez/skillsUltra-compressed communication mode. Cuts ~75% of tokens while keeping full technical accuracy by speaking like a caveman.
Frontend design skill for UI/UX implementation
Comprehensive UI/UX design plugin for mobile (iOS, Android, React Native) and web applications with design systems, accessibility, and modern patterns
Memory compression system for Claude Code - persist context across sessions
Marketing skills for AI agents — conversion optimization, copywriting, SEO, paid ads, ad creative, and growth
Standalone image generation plugin using Nano Banana MCP server. Generates and edits images, icons, diagrams, patterns, and visual assets via Gemini image models. No Gemini CLI dependency required.