<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Muhammad Usman</title>
    <description>The latest articles on DEV Community by Muhammad Usman (@usmangq).</description>
    <link>https://dev.to/usmangq</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F304991%2Ffa227260-ad3c-40c2-bd0e-ee4c7911da28.jpeg</url>
      <title>DEV Community: Muhammad Usman</title>
      <link>https://dev.to/usmangq</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/usmangq"/>
    <language>en</language>
    <item>
      <title>A skill nobody reaches for is dead weight</title>
      <dc:creator>Muhammad Usman</dc:creator>
      <pubDate>Fri, 24 Jul 2026 20:30:59 +0000</pubDate>
      <link>https://dev.to/usmangq/a-skill-nobody-reaches-for-is-dead-weight-2l1f</link>
      <guid>https://dev.to/usmangq/a-skill-nobody-reaches-for-is-dead-weight-2l1f</guid>
      <description>&lt;p&gt;Same task. Two ways of asking. Two very different results. That was the moment it clicked for me, and it has bugged me ever since.&lt;/p&gt;

&lt;p&gt;I gave my AI coding agent something to do, got back work that was fine but not good, rephrased the request, and got back exactly what I wanted. Nothing else changed. Same model, same repo, same afternoon. The only variable was me, and how I happened to frame it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The model was fine. I was the variable.
&lt;/h2&gt;

&lt;p&gt;That is an uncomfortable thing to admit, because it means the quality of my output was riding on whether I remembered the right way to ask on any given day. On a good day I pointed the agent at the failure log first, told it to reproduce before fixing, reminded it of the pattern we already use. On a distracted day I forgot half of that and got half the result.&lt;/p&gt;

&lt;p&gt;The knowledge of how to do the work well existed. It just lived in my head, and only when I was paying attention. Nowhere I could reuse it. Nowhere anyone else could either.&lt;/p&gt;

&lt;h2&gt;
  
  
  Now picture a whole team doing that
&lt;/h2&gt;

&lt;p&gt;For one person this is just friction you learn to live with. Scale it to a team and it turns into something worse. Everyone drives the agent a little differently. One person knows the trick that gets clean results. Another doesn't. One remembers the generator exists and another hand-writes the thing it would have scaffolded correctly.&lt;/p&gt;

&lt;p&gt;The output stops being a function of the tool and starts being a function of who is holding the keyboard. That is the real cost, and it hides well, because on any given day the work looks fine. It is the variance that gets you, not the average.&lt;/p&gt;

&lt;h2&gt;
  
  
  So I wrote the good version down
&lt;/h2&gt;

&lt;p&gt;I started capturing the ways of working that actually produced good results, as small reusable skills the agent could pick up on its own. Not a wiki page nobody opens. Not one giant instructions file that scrolls past the point of being read. Just focused playbooks, each describing how one kind of task should go. How to chase down a hard bug. How to build something test-first. How to turn a rough idea into a proper spec before a line of code gets written.&lt;/p&gt;

&lt;p&gt;The part that mattered most was making them easy to reach for. I added a single front door, a router, so nobody has to memorize a catalog. You describe what you are about to do and it points you at the right playbook. All of it is opt-in and made of plain text, which sounds like a small detail but isn't. When a playbook is wrong, fixing it is a one-line change, not a debate.&lt;/p&gt;

&lt;p&gt;Matt Pocock's thinking on skills, and on where automation is actually worth adding, shaped a lot of how I approached this (&lt;a href="https://x.com/mattpocockuk" rel="noopener noreferrer"&gt;@mattpocockuk&lt;/a&gt;). The idea that stuck: a skill only earns its keep if the agent reaches for it at the right moment. Writing it is the easy half. Making it get used is the real work.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed wasn't speed
&lt;/h2&gt;

&lt;p&gt;Before, every session started cold. The method lived in whoever was at the keyboard that day. Now the method is the same no matter who asks. The agent runs the same disciplined loop on a bug whether I kick it off or a teammate does.&lt;/p&gt;

&lt;p&gt;There is some speed in that, but speed is not the point. Predictability is. I stopped spending attention on remembering how to ask, and I stopped quietly worrying that a good result today would be an average one next week.&lt;/p&gt;

&lt;p&gt;Two things surprised me. A skill nobody reaches for is dead weight, so the router ended up mattering as much as the skills. And the ones that earn their place are almost always the boring repeated tasks, not the clever edge cases I thought I was building for.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you're the one deciding this for a team
&lt;/h2&gt;

&lt;p&gt;You do not standardize how a team uses AI by publishing a policy document. Nobody reads it, and it is stale a week later. You standardize it by making the good path the default path, so the right way to do something is also the easy way.&lt;/p&gt;

&lt;p&gt;That is cheap to try. Low risk, easy to change, easy to throw away whatever doesn't prove useful. For something that quietly sets the quality of a growing share of your team's work, that is a trade worth making.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>automation</category>
      <category>devtools</category>
      <category>agents</category>
    </item>
    <item>
      <title>AI-Driven Playwright E2E Tests From One Reference Doc</title>
      <dc:creator>Muhammad Usman</dc:creator>
      <pubDate>Mon, 20 Jul 2026 11:11:17 +0000</pubDate>
      <link>https://dev.to/usmangq/ai-driven-playwright-e2e-tests-from-one-reference-doc-5e7m</link>
      <guid>https://dev.to/usmangq/ai-driven-playwright-e2e-tests-from-one-reference-doc-5e7m</guid>
      <description>&lt;h2&gt;
  
  
  Writing E2E Tests With One Doc Instead of New Tooling
&lt;/h2&gt;

&lt;p&gt;We had a growing monorepo with two frontend apps and zero end-to-end coverage. The blocker was never Playwright itself. It was that every new feature meant babysitting an AI agent through the tests, click by click, and the output still needed rewriting by hand.&lt;/p&gt;

&lt;p&gt;Here is what actually fixed it, and the part I got wrong on the first try.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a dedicated package, not a shared test util
&lt;/h2&gt;

&lt;p&gt;The first instinct was to drop Playwright into the existing shared testing package. That does not work, for boring but real reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The unit-test runner and Playwright's runner cannot cohabit in one package.&lt;/li&gt;
&lt;li&gt;E2E runs must not be build-cached, while unit tests are cacheable. One package can't be both.&lt;/li&gt;
&lt;li&gt;Browser binaries and report output have no business leaking into a shared utility package.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the e2e suite is its own package, built from scratch. That separation is what let the rest of the decisions stay clean.&lt;/p&gt;

&lt;h2&gt;
  
  
  The structure that made tests cheap to write
&lt;/h2&gt;

&lt;p&gt;Three rules, enforced by the setup rather than by review comments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Selectors live only in Page Object Models.&lt;/strong&gt; Spec files never contain a raw locator.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Page objects are injected as fixtures.&lt;/strong&gt; No manual instantiation in a spec, ever.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auth runs once.&lt;/strong&gt; A setup project logs in, saves the session state to disk, and every test loads it. No login flow inside a test.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is that a spec reads like the user story and nothing else:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user can open the create form&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;createItemPage&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;createItemPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;createItemPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;heading&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeVisible&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Already authenticated, page object already wired in, no selector in sight.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part I got wrong first
&lt;/h2&gt;

&lt;p&gt;With the structure in place, I expected the AI-assisted authoring to be the easy win. It was the opposite. Pointing Codegen and the agent at a page produced tests that looked plausible and were quietly wrong. The agent guessed expected values it had no way to know, and every generated spec came back to my desk for a manual rewrite. It was slower than just writing them myself.&lt;/p&gt;

&lt;p&gt;The missing piece was context. The agent knew how to click a button. It did not know what the feature was supposed to &lt;em&gt;do&lt;/em&gt; — the state machine, the validation limits, which behaviors were correct and which were known bugs.&lt;/p&gt;

&lt;p&gt;So I wrote a skill for one feature that spelled all of that out: the flows, the rules, the routes, the confirmed bugs. The next tests it wrote were good. Not "good for AI" good. Better than what I was writing by hand, because it now had the right direction and never lost the thread halfway through a complex flow.&lt;/p&gt;

&lt;p&gt;Then I generalized it.&lt;/p&gt;

&lt;h2&gt;
  
  
  One doc per feature, not a skill per feature
&lt;/h2&gt;

&lt;p&gt;A skill per feature does not scale. The insight was that the &lt;em&gt;skill&lt;/em&gt; was generic; only the &lt;em&gt;facts&lt;/em&gt; were feature-specific. So I split them.&lt;/p&gt;

&lt;p&gt;The authoring engine became one reusable skill. It reads a per-feature reference doc, discovers the routes, reuses or extends the page objects, drives the real app, captures the actual outcomes as assertions, then runs and self-heals the spec. On top of that sits a thin layer: the official Playwright browser-driving skill for the low-level interaction, and one dedicated skill for the single most complex domain that earned extra shortcuts.&lt;/p&gt;

&lt;p&gt;What a new feature needs now is one document: entities, state machine, validation rules, and a numbered list of known bugs. That is it. The reference doc is the contract. If it does not exist, the agent is told to stop and ask for it instead of inventing rules from the UI, which is exactly the failure mode that cost me the first week.&lt;/p&gt;

&lt;p&gt;Before: walk the agent through every flow, then rewrite the output.&lt;br&gt;
After: write one ground-truth doc, point the generic skill at it, review real tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  The reusable idea
&lt;/h2&gt;

&lt;p&gt;The lesson had nothing to do with Playwright. Agents do not fail e2e work because they can't drive a browser. They fail because they guess at behavior no one wrote down. Encode the business truth in a document the agent is forced to read, keep the authoring engine generic, and adding coverage for the next feature costs one doc instead of a new pile of tooling.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>playwright</category>
      <category>testing</category>
      <category>automation</category>
    </item>
  </channel>
</rss>
