[{"id":3,"date":"2021-12-22T14:29:08","date_gmt":"2021-12-22T14:29:08","guid":{"rendered":"https:\/\/alopezari.com\/2021\/12\/22\/hello-world\/"},"modified":"2026-03-03T21:33:12","modified_gmt":"2026-03-03T20:33:12","slug":"hello-world","status":"publish","type":"post","link":"https:\/\/alopezari.com\/2021\/12\/22\/hello-world\/","title":{"rendered":"Your AI Skills Might Have a Quality Problem"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Remember the first time you saw a 500-line function that fetched data, validated it, transformed it, rendered HTML, and sent an email? You knew instinctively that something was wrong, even if you couldn&#8217;t articulate why yet.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That&#8217;s where most AI agent skills are right now.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you&#8217;re working with agentic coding tools \u2014 Claude Code, Cursor, custom MCP setups \u2014 you&#8217;re probably writing skill files that started as a clean paragraph of instructions and slowly mutated into sprawling megaprompts. A single skill that reads your codebase, analyzes patterns, generates documentation, formats it as markdown, and exports a PDF. All in one file. All competing for the same context window.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We solved this in software engineering decades ago. The principles that made code maintainable \u2014 separation of concerns, composition over modification, depending on abstractions \u2014 apply directly to skill design. Not as a rigid framework, but as instincts worth developing.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Cost of a Monolithic Skill<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">When a skill does too many things, every problem compounds. You can&#8217;t debug it because you don&#8217;t know which part broke. You can&#8217;t reuse pieces of it because the pieces aren&#8217;t separable. And in the agent world, there&#8217;s a cost that traditional code doesn&#8217;t have: <strong>context window is your runtime memory<\/strong>. A bloated skill leaves no room for the actual work.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The fix is the same one we&#8217;ve always known: give each skill a single job. A file reader reads files. A chart generator generates charts. A doc builder builds docs. When you need all three, compose them \u2014 don&#8217;t merge them.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Composition Over Modification<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Here&#8217;s a scenario that plays out constantly: your doc-builder skill works great, but now you also need markdown output. The instinct is to open it up and add markdown handling.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Resist that instinct. Create a separate markdown-renderer and compose it with the existing skill. This is the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Open%E2%80%93closed_principle\">Open\/Closed Principle<\/a> applied to prompts, and it matters even more here than in traditional code. When you modify a working skill, you&#8217;re not just risking regressions \u2014 you&#8217;re changing how an LLM interprets an entire instruction set. The blast radius is unpredictable.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Abstract the What from the How<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">This is where things get interesting, because the AI tooling landscape moves <em>fast<\/em>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If your report-generation skill says &#8220;use the recharts-chart-v2 skill to produce charts,&#8221; you&#8217;ve created a hard dependency on a specific tool that might not exist in three months. If instead it says &#8220;this skill needs chart output from tabular data,&#8221; any charting skill can fulfill that contract.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The same logic applies to LLM providers. A summarization skill shouldn&#8217;t be wired to a specific model&#8217;s quirks. Define what the output looks like \u2014 a JSON schema, a structured format \u2014 and let any implementation satisfy it. When you inevitably switch providers or upgrade models, your workflows survive.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is <a href=\"https:\/\/en.wikipedia.org\/wiki\/Dependency_inversion_principle\">Dependency Inversion<\/a> and <a href=\"https:\/\/en.wikipedia.org\/wiki\/Liskov_substitution_principle\">Liskov Substitution<\/a> working together: depend on outcomes, not implementations, and make skills swappable by standardizing their interfaces.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Keep Dependencies Honest<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A workflow that only reads files shouldn&#8217;t load a massive &#8220;file-io&#8221; skill that also handles writing, deleting, and converting. Every unnecessary capability you pull into context is dead weight \u2014 tokens spent on instructions the agent will never use.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This matters less in traditional code where unused imports are just a minor annoyance. In agent skills, unused context actively degrades performance. Be surgical about what each skill depends on.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">A Mental Model for Layers<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">I think about skills in four rough layers:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Workflows<\/strong> sit at the top \u2014 they orchestrate (&#8220;generate a tech report from this repo&#8221;). <strong>Capabilities<\/strong> are domain-level tasks they delegate to (&#8220;build a document,&#8221; &#8220;analyze code&#8221;). <strong>Utilities<\/strong> are the reusable building blocks (&#8220;read files,&#8221; &#8220;transform data,&#8221; &#8220;handle errors&#8221;). <strong>Primitives<\/strong> are what the runtime gives you \u2014 LLM calls, tool execution, shell access, APIs.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The rule: each layer delegates downward, never reimplements what&#8217;s below it. If your workflow contains inline file-reading logic, that&#8217;s a utility trying to escape.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In practice, 3-4 layers is the ceiling. Each layer of composition may mean another LLM call, and quality degrades as you go deeper. Not every pattern deserves its own skill \u2014 sometimes inlining is the right call.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Smells I Keep Seeing<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A few recurring patterns that signal a skill needs rethinking:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>The God Skill<\/strong> that reads, processes, formats, and delivers \u2014 all in one prompt. Split by concern.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Copy-pasted error handling<\/strong> across multiple skills. If three skills handle file-not-found the same way, that&#8217;s a shared utility waiting to be extracted.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Hidden dependencies<\/strong> that cause cryptic failures. If your skill needs a specific tool to be available, say so at the top. Don&#8217;t make the agent (or the human) discover it through trial and error.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Context bloat<\/strong> \u2014 instructions so verbose that by the time the agent finishes reading them, there&#8217;s barely any room left for the actual task.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Where the Analogy Breaks<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">These principles transfer well, but not perfectly. A few important differences:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Skills are non-deterministic. You can&#8217;t assert exact outputs. Testing means evaluating whether the output has the right shape, contains the right information, and meets quality thresholds. It&#8217;s closer to QA than unit testing.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Composition has real monetary and latency cost. Every skill invocation may trigger an LLM call. The question isn&#8217;t &#8220;can I decompose this further?&#8221; but &#8220;is the decomposition worth the overhead?&#8221;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">And the platform keeps shifting underneath us. This is precisely why principles beat rigid specifications. Good design habits survive platform changes. Overfitted tooling becomes technical debt the moment the next paradigm arrives.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Bottom Line<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Write skills the way you&#8217;d write good code: focused, composable, documented against their interfaces, and designed to be replaced. Start with a <code>SKILL.md<\/code>. Split when it grows. Depend on outcomes, not implementations. Respect the context window.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">These aren&#8217;t rules \u2014 they&#8217;re instincts worth building. The same instincts that made you wince at that 500-line function will serve you well here too.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Remember the first time you saw a 500-line function that fetched data, validated it, transformed it, rendered HTML, and sent an email? You knew instinctively&hellip;<\/p>\n","protected":false},"author":215243893,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"advanced_seo_description":"","jetpack_seo_html_title":"","jetpack_seo_noindex":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"{title}\n\n{excerpt}\n\n{url}","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"_wpas_customize_per_network":false,"jetpack_post_was_ever_published":false},"categories":[1771],"tags":[],"class_list":["post-3","post","type-post","status-publish","format-standard","hentry","category-sin-categoria","animate-in"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":false,"jetpack_likes_enabled":null,"jetpack_shortlink":"https:\/\/wp.me\/pdBy0n-3","_links":{"self":[{"href":"https:\/\/alopezari.com\/wp-json\/wp\/v2\/posts\/3","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/alopezari.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/alopezari.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/alopezari.com\/wp-json\/wp\/v2\/users\/215243893"}],"replies":[{"embeddable":true,"href":"https:\/\/alopezari.com\/wp-json\/wp\/v2\/comments?post=3"}],"version-history":[{"count":3,"href":"https:\/\/alopezari.com\/wp-json\/wp\/v2\/posts\/3\/revisions"}],"predecessor-version":[{"id":128,"href":"https:\/\/alopezari.com\/wp-json\/wp\/v2\/posts\/3\/revisions\/128"}],"wp:attachment":[{"href":"https:\/\/alopezari.com\/wp-json\/wp\/v2\/media?parent=3"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/alopezari.com\/wp-json\/wp\/v2\/categories?post=3"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/alopezari.com\/wp-json\/wp\/v2\/tags?post=3"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}]