<?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: Valentine Tikhomirov</title>
    <description>The latest articles on DEV Community by Valentine Tikhomirov (@zemant91).</description>
    <link>https://dev.to/zemant91</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%2F4139040%2F982c25cb-8eab-4f82-b3b2-2a4033b06111.jpg</url>
      <title>DEV Community: Valentine Tikhomirov</title>
      <link>https://dev.to/zemant91</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zemant91"/>
    <language>en</language>
    <item>
      <title>I stopped prompting and started building a harness</title>
      <dc:creator>Valentine Tikhomirov</dc:creator>
      <pubDate>Wed, 23 Sep 2026 11:37:27 +0000</pubDate>
      <link>https://dev.to/zemant91/i-stopped-prompting-and-started-building-a-harness-2hg2</link>
      <guid>https://dev.to/zemant91/i-stopped-prompting-and-started-building-a-harness-2hg2</guid>
      <description>&lt;p&gt;For the last few months I've been using AI agents in almost every part of my React Native work. At some point I noticed I was writing the same instructions over and over: how I want projects set up, what a good refactoring looks like, what to check before shipping. Every new session started from zero.&lt;/p&gt;

&lt;p&gt;So I started turning those instructions into a harness: a set of skills and agents that encode how I actually work. It's still in alpha, I use it daily on my own projects, and here's how it's built and what I've learned so far.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a plugin and not a folder of prompts
&lt;/h2&gt;

&lt;p&gt;My first version was just files copied into &lt;code&gt;~/.claude&lt;/code&gt;. Now the harness is a proper Claude Code plugin in its own git repo. Every skill and agent is called with an &lt;code&gt;rnmh:&lt;/code&gt; prefix, so it's clear what comes from the harness and what doesn't.&lt;/p&gt;

&lt;p&gt;The biggest change wasn't organizational, though. Once each task had its own dedicated skill, the agent's answers became noticeably more structured, and the results got better with them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's inside right now
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Project bootstrap.&lt;/strong&gt; Deliberately minimal: it fixes only strict TypeScript and the folder organization I choose, and asks about everything else per project. An opinionated template ages badly; a short interview doesn't.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Refactoring skill + agent.&lt;/strong&gt; Built on the catalog from Martin Fowler's &lt;em&gt;Refactoring&lt;/em&gt; (2nd edition), grouped by its chapters. The key decision: it applies refactorings instead of just listing code smells.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-project consistency agent.&lt;/strong&gt; I work on several RN projects in parallel. This agent compares them for duplicated code and naming drift, without assuming there's a shared library.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design-to-code, architecture review, testing and test coverage&lt;/strong&gt; round out the core set.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Diagnostics, release checklist, security review and RN upgrades&lt;/strong&gt; are the newest additions. They're written, but I haven't battle-tested them on a real project yet, so they're next in line.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  First real test
&lt;/h2&gt;

&lt;p&gt;I ran the refactoring agent on my own side project, a headache tracker that's currently in alpha. The home screen had grown into a classic &lt;em&gt;Long Function&lt;/em&gt;: one &lt;code&gt;Home()&lt;/code&gt; component of ~330 lines with 5 &lt;code&gt;useState&lt;/code&gt;, 5 &lt;code&gt;useEffect&lt;/code&gt;, 3 async handlers and a three-way JSX branch, all inline.&lt;/p&gt;

&lt;p&gt;Before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;openAttack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setOpenAttack&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Attack&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;recent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setRecent&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Attack&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setNow&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;systemClock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loadError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoadError&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;reduceMotion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setReduceMotion&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&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="nx"&gt;AccessibilityInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isReduceMotionEnabled&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;setReduceMotion&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;AccessibilityInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;reduceMotionChanged&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;setReduceMotion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
  &lt;span class="c1"&gt;// ...4 more effects, 3 async handlers, ~150 lines of inline JSX&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reduceMotion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useReduceMotion&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="c1"&gt;// ...same effects and handlers, unchanged&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;middle&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;openAttack&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OngoingAttackCard&lt;/span&gt;
          &lt;span class="na"&gt;openAttack&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;openAttack&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;pulseStyle&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pulseStyle&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;onSetIntensity&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleSetIntensity&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;recent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RecentAttacksList&lt;/span&gt; &lt;span class="na"&gt;recent&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;recent&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Text&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;emptyText&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;home.noAttacksYet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&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;Every change mapped to a named refactoring from the catalog:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Extract Component:&lt;/strong&gt; &lt;code&gt;IntensityPicker&lt;/code&gt;, &lt;code&gt;OngoingAttackCard&lt;/code&gt;, &lt;code&gt;RecentAttacksList&lt;/code&gt;, &lt;code&gt;HomeActions&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extract Function into hooks:&lt;/strong&gt; &lt;code&gt;useReduceMotion&lt;/code&gt;, plus &lt;code&gt;useDictation&lt;/code&gt; and a generic &lt;code&gt;useKeyboardVisible&lt;/code&gt; on the log-input screen&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Move Function:&lt;/strong&gt; &lt;code&gt;formatTime()&lt;/code&gt; went to the shared formatting module, so it wouldn't be duplicated in two new components&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Remove Dead Code:&lt;/strong&gt; an unused style and a dead import it found along the way&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;Home()&lt;/code&gt; went from ~330 to ~150 lines. The total line count actually grew a bit because of new files and imports, and that's fine: the point is that each piece now has one job. Behavior didn't change, since the agent kept refactoring strictly separate from feature work, and &lt;code&gt;tsc&lt;/code&gt; and &lt;code&gt;eslint&lt;/code&gt; came back clean.&lt;/p&gt;

&lt;p&gt;One honest caveat: the agent only ran static checks, not the app, so checking the screens on a simulator was still on me.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I've learned so far
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Narrow skills beat one giant prompt.&lt;/strong&gt; A skill that does one job with clear steps gives far more consistent output than a long general instruction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make it act, not just advise.&lt;/strong&gt; A reviewer that only lists problems creates homework. One that makes the change and explains it saves time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Understanding the project is still the weak spot.&lt;/strong&gt; Agents struggle to read a codebase and actually use that knowledge later. They can miss existing features, so I often have to steer them. Tools like graphify, which gives the agent a map of the codebase, help a lot here, but it's not solved.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;I'm planning to open the harness to other React Native developers. If you're building something similar, or would want a toolkit like this, I'd love to hear what you'd expect from it in the comments.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mobile</category>
      <category>productivity</category>
      <category>reactnative</category>
    </item>
  </channel>
</rss>
