<?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>My harness taught the agent how to build. Now it needs to see.</title>
      <dc:creator>Valentine Tikhomirov</dc:creator>
      <pubDate>Thu, 08 Oct 2026 20:55:51 +0000</pubDate>
      <link>https://dev.to/zemant91/my-harness-taught-the-agent-how-to-build-now-it-needs-to-see-2jpg</link>
      <guid>https://dev.to/zemant91/my-harness-taught-the-agent-how-to-build-now-it-needs-to-see-2jpg</guid>
      <description>&lt;p&gt;At the end of my &lt;a href="https://dev.to/zemant91/my-agent-built-a-feature-then-tapped-through-it-on-the-simulator-4ke6"&gt;last post&lt;/a&gt; I said the next step was letting my pipeline iterate on its own review findings. I didn't get there. I ran into something more basic first: the part of the harness that lets the agent use the app.&lt;/p&gt;

&lt;p&gt;That part, &lt;code&gt;rn-app-driver&lt;/code&gt;, reads the React component tree and taps the simulator so the agent can check its own work. It did its job. But the more I used it, the more it felt like the wrong shape for the problem. So I pulled it out of the harness and started building a separate tool around it.&lt;/p&gt;

&lt;p&gt;This post is about why, and about a few things an agent simply can't learn from reading your code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the driver stopped fitting into a skill
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Only the agent could see it.&lt;/strong&gt; The driver ran inside the agent's session. While it was tapping through my app, I was looking at a terminal. I only found out what it actually did by reading the log afterwards.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It only worked in one agent.&lt;/strong&gt; It was built as a Claude Code skill. I also use Codex, and I'd like the same capability to work with whatever agent comes next.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Safety by word list doesn't hold.&lt;/strong&gt; After the last post, two readers pointed out the same weak spot: the driver decided whether an action was risky by its label. "Delete" and "Save" stopped for confirmation, but a button labelled "Done" could change data and sail right through. They were right. The real fix isn't a better word list. It's putting the decision in front of a human who can see the screen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A component name isn't a location.&lt;/strong&gt; The driver told the agent "this is &lt;code&gt;HomeActions/log-attack&lt;/code&gt;". What the agent actually needs next is "this is &lt;code&gt;HomeActions.tsx:42&lt;/code&gt;", so it can open the right file instead of searching for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Things an agent can't see from your code
&lt;/h2&gt;

&lt;p&gt;While building this, I kept measuring what the running app tells you that the source doesn't. Three findings stood out. All measured on one Mac, iOS simulator, RN 0.87 with React 19.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. JS errors leave no trace in the iOS system log.&lt;/strong&gt; I recorded 90 seconds of normal app use: 3,498 native log events. Every single one came from Apple's frameworks. Zero from the app, React Native or Hermes, including during deliberate JS errors. If your agent "checks the device logs", it's checking the wrong place for anything that happens in JavaScript.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. In React 19, component locations can be off by 20 lines.&lt;/strong&gt; React 19 removed &lt;code&gt;_debugSource&lt;/code&gt;, the old way to map an element back to its file and line. The replacement points elements rendered inside &lt;code&gt;.map(...)&lt;/code&gt; at the start of the callback, not at the tag. In a real app that was 8 out of 22 points I tested, with the actual tag 14–24 lines further down. An agent trusting that line edits the wrong place.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. "The screen changed after the tap" proves nothing.&lt;/strong&gt; The simulator's video stream keeps sending around 53 frames per second even when nothing on screen moves. So "a new frame arrived" is not evidence that your tap landed. What did work: comparing frame &lt;em&gt;size&lt;/em&gt; against the idle background. A real UI reaction produced frames of 4–29 KB, idle ones were well under 2 KB.&lt;/p&gt;

&lt;p&gt;None of this is visible in a diff. All of it matters when an agent claims "I checked, it works".&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'm building
&lt;/h2&gt;

&lt;p&gt;A desktop app for React Native development where the agent and I look at the same running app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;For the agent:&lt;/strong&gt; the component tree with real &lt;code&gt;file:line&lt;/code&gt; locations, logs and errors from the app, the simulator screen, taps, gestures and typing. It connects over MCP, so it works with Claude Code and Codex today, and with any MCP-capable agent in principle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For me:&lt;/strong&gt; the live simulator, what the agent is doing on it, and an approval card for risky actions. The agent asks, I see the screen and the action, I decide.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One rule I won't bend:&lt;/strong&gt; the tool never types into my terminal for me. It can paste text, but Enter is always mine. I learned this the hard way when a test typed a message plus Enter into a terminal running an agent in auto mode, and kicked off a model turn nobody asked for.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first stage, the part the agent talks to, already works and has been tested with both Claude Code and Codex. The desktop app is in progress: live iOS simulator at around 48 fps, and clicking anywhere on the screen finds the component under that point in about 5 ms.&lt;/p&gt;

&lt;p&gt;The harness isn't going anywhere. It stays the "how to build" part: skills, review agents, pipelines. The new tool becomes its eyes and hands.&lt;/p&gt;

&lt;h2&gt;
  
  
  An honest result
&lt;/h2&gt;

&lt;p&gt;To check that the tool actually helps, I planted a bug in my gym app and asked both agents to find it. They found it in 6 out of 6 runs. Then I realised they found it by reading the code, without needing the tool at all.&lt;/p&gt;

&lt;p&gt;That's the lesson I keep coming back to. If you want to show that runtime tooling helps an agent, you have to test it on bugs that aren't visible in the source: wrong state, timing, a layout that only breaks on device. Otherwise you're measuring how well the model reads code.&lt;/p&gt;

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

&lt;p&gt;I'll write up the most surprising findings separately, with numbers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;streaming the iOS simulator into an Electron app at ~50 fps (screenshots topped out at 2.3 fps);&lt;/li&gt;
&lt;li&gt;why an environment variable from your terminal never reaches your MCP server in Codex;&lt;/li&gt;
&lt;li&gt;a trap for anyone writing MCP servers: what Claude Code actually shows the model when a tool returns both text and structured content.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And a question for you: how do you check what your agent did in the app right now? Do you open the simulator yourself after every run, or trust the summary?&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>ai</category>
      <category>mobile</category>
      <category>devtools</category>
    </item>
    <item>
      <title>My agent built a feature, then tapped through it on the simulator</title>
      <dc:creator>Valentine Tikhomirov</dc:creator>
      <pubDate>Mon, 28 Sep 2026 16:48:08 +0000</pubDate>
      <link>https://dev.to/zemant91/my-agent-built-a-feature-then-tapped-through-it-on-the-simulator-4ke6</link>
      <guid>https://dev.to/zemant91/my-agent-built-a-feature-then-tapped-through-it-on-the-simulator-4ke6</guid>
      <description>&lt;p&gt;In my &lt;a href="https://dev.to/zemant91/i-stopped-prompting-and-started-building-a-harness-2hg2"&gt;previous post&lt;/a&gt; I tested a single skill from my React Native harness: a refactoring agent. This time I ran the whole thing end to end for the first time. One confirmation from me, then the agent planned a feature, built it, tested it, tapped through it on the iOS simulator, and ran a review pass on its own code.&lt;/p&gt;

&lt;p&gt;Here's how it's wired and what actually happened.&lt;/p&gt;

&lt;h2&gt;
  
  
  One checkpoint, then hands-off
&lt;/h2&gt;

&lt;p&gt;The skill is called &lt;code&gt;feature-pipeline&lt;/code&gt;. Before touching code, it sends me a single message with the proposed scope, the design direction, and how data, state and errors will be handled. I approve once, and from then on it doesn't stop to ask:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build the UI and logic.&lt;/li&gt;
&lt;li&gt;Test it.&lt;/li&gt;
&lt;li&gt;Verify on device: drive the running app on the simulator.&lt;/li&gt;
&lt;li&gt;Review: call the harness's other agents as real subagents (refactoring, test coverage, architecture review, plus instrumentation agents if the feature needs them).&lt;/li&gt;
&lt;li&gt;Report: one consolidated list of what was done and what's still open.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It never merges to &lt;code&gt;main&lt;/code&gt; and never touches deployment or store submission. Those are hard boundaries, not settings.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part I'm most excited about: how the agent sees the app
&lt;/h2&gt;

&lt;p&gt;Step 3 uses another skill, &lt;code&gt;rn-app-driver&lt;/code&gt;. Most tools that let an agent use a mobile app work from screenshots: take a picture, guess where the button is, tap coordinates. That's slow and expensive in context.&lt;/p&gt;

&lt;p&gt;The driver reads the app's React component tree straight from Hermes instead. It takes around 10 ms and 1–3k characters, and looks like this (from my headache tracker):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;screen: Home
@Home/scroll ScrollView [0,62,402,723]
  "Saturday" "September 26"
  HomeActions
    @HomeActions/log-attack Pressable "Log attack" icon:Plus [24,561,354,84]
TabBar
  @TabBar/history Pressable "History" icon:TabHistory [101,796,100,44]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every &lt;code&gt;@id&lt;/code&gt; is something the agent can act on, with stable ids across runs and a real frame in points. Taps are real touch events on the simulator (via AXe), aimed at those frames, so the agent never guesses coordinates. Screenshots are still there for visual checks, just not for navigation.&lt;/p&gt;

&lt;p&gt;A few rules make it usable rather than scary:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One action per command. Each action waits for the UI to settle and prints the new screen, and the agent checks it before deciding the next step. No planning five taps ahead on screens it hasn't seen.&lt;/li&gt;
&lt;li&gt;A safety policy. Anything whose label looks like it changes data (save, delete, log, edit, and so on) stops with an error until I explicitly confirm that specific action.&lt;/li&gt;
&lt;li&gt;Everything is logged. Each session writes an action log, and a walked flow can be saved as a test case and replayed later. The replay exits with 0 or 1, so it can eventually become a regression gate in CI.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The run
&lt;/h2&gt;

&lt;p&gt;The target was a new "Exercises list" screen in my gym rep counter app, another side project.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build: about 5–7 minutes from approval to working code.&lt;/li&gt;
&lt;li&gt;On-device check: a few more minutes, and it took several runs. Verifying a screen like this needs the app in exactly the right state with the right data, and getting there reliably is the hard part.&lt;/li&gt;
&lt;li&gt;Review agents: found only code smells, nothing structural.&lt;/li&gt;
&lt;li&gt;Result: a report with recommendations prioritized by importance. No PR.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last one was my decision, not a failure. With this much access, a run can end in many ways, and for now I want the irreversible steps (committing, pushing, opening a PR) to stay with a human. A full cycle with builds and pushes is on the list to test later, deliberately and separately.&lt;/p&gt;

&lt;h2&gt;
  
  
  What surprised me
&lt;/h2&gt;

&lt;p&gt;The speed and autonomy, honestly. Scoping was sensible, it picked the right agents, and it really did use the app on the simulator instead of just reading its own code back.&lt;/p&gt;

&lt;p&gt;But it made mistakes, and the interesting part is that it pointed them out itself in the final report as things worth fixing. Which raises the obvious question: if the agent already knows what's wrong, why stop after one pass?&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Read the structure, not the pixels. For navigating an app, the component tree beats screenshots on speed, cost and reliability. Screenshots are for checking how things look.&lt;/li&gt;
&lt;li&gt;State is the real problem of on-device testing. Tapping is easy. Reliably getting the app into the exact state a check needs is not.&lt;/li&gt;
&lt;li&gt;An agent that lists its own mistakes deserves a second pass. Running the implement-and-review cycle several times, not once, is my next priority.&lt;/li&gt;
&lt;li&gt;Keep the irreversible steps human, for now. Autonomy up to a tested, reviewed result is great. What happens with that result is still my call.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;ul&gt;
&lt;li&gt;Let the pipeline iterate on its own recommendations for a few cycles and compare the result with a single pass.&lt;/li&gt;
&lt;li&gt;Start saving walked flows as replayable test cases and keeping the logs, so the next posts can show real traces and numbers instead of summaries.&lt;/li&gt;
&lt;li&gt;Test the full cycle, including commits and pushes, on a project where that's safe.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're letting agents drive your app on a simulator: how do you deal with test data and state? That's the part I'd most like to compare notes on.&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>ai</category>
      <category>testing</category>
      <category>mobile</category>
    </item>
    <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>
