<?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: Michał Król</title>
    <description>The latest articles on DEV Community by Michał Król (@krolmic).</description>
    <link>https://dev.to/krolmic</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%2F4238513%2F2ec72402-371f-4551-8e06-8659396c0d07.png</url>
      <title>DEV Community: Michał Król</title>
      <link>https://dev.to/krolmic</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/krolmic"/>
    <language>en</language>
    <item>
      <title>Flutter App Redesign with pen.dev and Claude Code Skills: From Pencil Designs to Verified Screens</title>
      <dc:creator>Michał Król</dc:creator>
      <pubDate>Wed, 11 Nov 2026 07:17:21 +0000</pubDate>
      <link>https://dev.to/krolmic/flutter-app-redesign-with-pendev-and-claude-code-skills-from-pencil-designs-to-verified-screens-397n</link>
      <guid>https://dev.to/krolmic/flutter-app-redesign-with-pendev-and-claude-code-skills-from-pencil-designs-to-verified-screens-397n</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Kurvenheld is a motorcycle app built in Flutter for iOS and Android. Together with the agency blindwerk I redesigned all of it: 23 screens, 28 design cells in pen.dev. It's live in the App Store and on Google Play.&lt;/li&gt;
&lt;li&gt;The first phase was manual and slow on purpose: research, scope, paper wireframes, type and colors, the first proposal screens. Under five days, and the right place to be slow.&lt;/li&gt;
&lt;li&gt;Then the math broke. Proposal speed times 28 cells, times review rounds, times translating every screen into Flutter: nowhere near my estimate.&lt;/li&gt;
&lt;li&gt;So I wrote five skills for the parts that repeat: redesign, update, sync, implement, verify. Claude Code and Codex share them, connected to the pen.dev MCP and the Marionette MCP. All screens redesigned in under five days, all screens implemented in under five days.&lt;/li&gt;
&lt;li&gt;Every skill plans first and waits for my OK. blindwerk reviewed the designs and the code, and we checked everything before release. The automation made the loop faster. It didn't take the people out of it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where this started
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.kurvenheld.de" rel="noopener noreferrer"&gt;Kurvenheld&lt;/a&gt; is an app for motorcyclists. It counts the curves you ride, tracks your tours, ranks you against other riders and lets groups run challenges against each other. It's built in Flutter for iOS and Android by &lt;a href="https://www.blindwerk.de" rel="noopener noreferrer"&gt;blindwerk – Digitale Architekten&lt;/a&gt;, a German digital agency I work with as a &lt;a href="https://krolmic.dev/mobile-app-development/" rel="noopener noreferrer"&gt;freelance Flutter developer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I knew the app well. In 2025 I had already rebuilt it with blindwerk, under the hood: new foundation, same UI. The screens people saw stayed exactly the way they were. This year came the other half, everything the user actually looks at.&lt;/p&gt;

&lt;p&gt;That's 23 screens. Five tabs (Discover, Ranking, Ride, Groups, Settings), seven detail screens (tour details, profiles, trophies, groups, challenges), four for onboarding and sign-in, three full-screen viewers and four system screens. Plus 11 bottom sheets and more dialogs than I care to count. In pen.dev it came to 28 cells, because empty states, wizard steps and some sheets each get a cell of their own.&lt;/p&gt;

&lt;p&gt;Mostly it was a view-layer rewrite: new widgets on top of the same state management, data layer, routing, map and GPS tracking. Mostly. Some screens changed so radically that the code behind them had to move too. Pretending otherwise would have given us a very pretty mess.&lt;/p&gt;

&lt;p&gt;This is what we started from:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Discover&lt;/th&gt;
&lt;th&gt;Ride&lt;/th&gt;
&lt;th&gt;Ranking&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftzxxt5rx2o7bfbr6reb1.webp" alt="Old Discover tab: a map of Badung, Bali with a 5 km search radius and a tour-count marker, above a sheet listing six tours for the location with a preview map, a photo, length, curves and elevation." width="780" height="1688"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq0ngqzb779i8opryxw19.webp" alt="Old Ride tab: a seven-segment curve counter at zero between yellow hazard stripes, distance and duration at zero, and Pause Tour and Finish Tour buttons." width="780" height="1688"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvie1hcumaij15x1ml493.webp" alt="Old Ranking tab: a HighScore and UserScore toggle, a year picker, the signed-in rider at rank 193, and the top riders with avatars and seven-segment scores." width="780" height="1688"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tour details&lt;/th&gt;
&lt;th&gt;My Profile&lt;/th&gt;
&lt;th&gt;Discover, tour selected&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffc6f402h6qpho32whi28.webp" alt="Old tour details screen: a black-and-white mountain-road header cut by a yellow diagonal, edit, bookmark and share buttons, the tour's statistics, a like row, a description and a route map." width="780" height="1688"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftxe239siliah54nr12sj.webp" alt="Old My Profile screen: a header photo with a yellow avatar, the rider's name, the 2026 rides, highscore and userscore counters, and Rides, Rankings, Trophies and Bookmarks tabs above a list of rides." width="780" height="1688"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2ykktkiivt38q15u6n9w.webp" alt="Old Discover tab with a selected tour: the route highlighted in yellow on the map with a 323 Curves label, a Search Here button, and a horizontal row of tour cards." width="780" height="1688"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What is pen.dev?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://pen.dev" rel="noopener noreferrer"&gt;pen.dev&lt;/a&gt; (formerly Pencil) is a design canvas that an AI agent can operate. The design is a &lt;code&gt;.pen&lt;/code&gt; file, plain JSON, sitting in the repo next to the app code. A local MCP server exposes the canvas to Claude Code, Codex and friends: they read the design, create screens and components, bind values to tokens and export screenshots of what they drew.&lt;/p&gt;

&lt;p&gt;You can still grab the mouse and move things yourself. You and the agent are editing the same file.&lt;/p&gt;

&lt;p&gt;For a redesign that's the whole point. The design system, all 28 cells and the Flutter code live in one repo, and the agent that just read a screen in the design file can open the Dart file that implements it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 1: slow on purpose
&lt;/h2&gt;

&lt;p&gt;No skills, no automation. I spent the first days looking at other apps, sketching on paper, going back and forth with blindwerk on scope, and settling typography and colors. Then I built the first proposal screens in pen.dev: a handful of screens that showed where the app could go. All of it in under five days.&lt;/p&gt;

&lt;p&gt;The prompts came out of a note I copy-pasted from. Every one carried the same three rules: every new component goes into the component library, variables instead of raw color values, reuse what exists before drawing anything new. That was enough discipline while there were few screens, and Claude Code with the pen.dev MCP gave me screens I could show the agency without touching up.&lt;/p&gt;

&lt;p&gt;I'd do this phase slowly again. The decisions made here, the direction, the type scale, the palette, the scope, are inherited by every screen that follows. You want to look around, sketch, argue about it, revise. Nothing here repeats, so nothing here is worth automating.&lt;/p&gt;

&lt;h2&gt;
  
  
  The moment the estimate broke
&lt;/h2&gt;

&lt;p&gt;The proposals got approved. I was happy for about an hour. Then I did the math for the rest.&lt;/p&gt;

&lt;p&gt;Proposal speed, times 28 cells. A review round with blindwerk after every batch, an adjustment round after every review. Then every approved screen translated into Flutter, built from a component library I was still building, without dropping anything the old views did quietly: guest gating tucked into tap handlers, pagination, analytics events, what happens when you swipe a sheet away, what a form hands back to the screen that opened it.&lt;/p&gt;

&lt;p&gt;The pace that was fine for a handful of proposal screens wasn't anywhere near the estimate for the whole app. And here's the thing: the slow part was already done. The decisions existed. What was left was repetition with a lot of rules attached, which is exactly what automation is good at.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't automate taste. Automate what comes after it.
&lt;/h2&gt;

&lt;p&gt;That's the rule I'd take into any redesign now. Taste, meaning the direction, the type, the colors, what the app should feel like, is human work, and you do it slowly. Executing against decided taste is process work. Process work with rules can be a skill.&lt;/p&gt;

&lt;p&gt;So instead of grinding through screens one by one, I wrote skills for the processes that would repeat most: redesigning a screen from the old one, changing a design after a review, implementing a finished design in Flutter, verifying the implementation against the design, and bringing the design file back in line when the implementation deliberately went its own way.&lt;/p&gt;

&lt;p&gt;What goes into a skill that never fit in a pasted prompt: the rules I kept repeating (tokens only, library first, reuse before building), the order of operations (read the live file before touching anything, plan, get my OK, then build), the things that went wrong once and must not go wrong again, and a way to test the skill itself.&lt;/p&gt;

&lt;p&gt;I used Anthropic's &lt;a href="https://github.com/anthropics/skills/blob/main/skills/skill-creator/SKILL.md" rel="noopener noreferrer"&gt;Skill Creator&lt;/a&gt; to write and iterate them. It drafts the SKILL.md, keeps it lean by pushing detail into reference files, and runs evals: prompts plus assertions about what the skill should produce. For the design skills the evals are plan-only dry runs. The agent plans and stops, so a test run never edits the design file, and every rewrite of a skill gets checked against the same prompts as the version before it.&lt;/p&gt;

&lt;h2&gt;
  
  
  One redesign loop, five skills
&lt;/h2&gt;

&lt;p&gt;Each skill owns one direction of truth. That turned out to be the most important design decision in the whole set: a skill that knows what its source of truth is can refuse to improvise.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Skill&lt;/th&gt;
&lt;th&gt;What it treats as truth&lt;/th&gt;
&lt;th&gt;What it changes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;kurvenheld-screen-redesign&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Screenshot of the old screen, a brief, optional design references&lt;/td&gt;
&lt;td&gt;A new screen in pen.dev, built on the design system&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;kurvenheld-screen-update&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A text brief, resolved against the live design file&lt;/td&gt;
&lt;td&gt;An existing pen.dev screen, with the component library kept in sync&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;kurvenheld-screen-sync&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Screenshot of the implemented app&lt;/td&gt;
&lt;td&gt;The pen.dev file, brought back in line with what shipped&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;kurvenheld-screen-implement&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The finished pen.dev screen&lt;/td&gt;
&lt;td&gt;The Flutter view layer, composed from the component library&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;kurvenheld-screen-verify&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Both: the running app and the pen.dev screen&lt;/td&gt;
&lt;td&gt;Nothing until I approve; then view-layer fixes via hot reload&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A screen usually moved through them in this order: redesign, a review round with blindwerk, update for the feedback, implement, verify. Sync is there because the loop is never perfectly clean. A few sheets shipped without ever being designed, a few shipped differently than designed, and a design file that lies is worse than no design file. So the app-to-design direction got a skill of its own.&lt;/p&gt;

&lt;p&gt;The skills belong to the client, so I'll describe what each one does rather than show it.&lt;/p&gt;

&lt;h3&gt;
  
  
  kurvenheld-screen-redesign
&lt;/h3&gt;

&lt;p&gt;Phase 1, turned into a repeatable process. I hand it a screenshot of the current screen, a short brief (what should change, what those three unlabeled numbers on the profile actually mean) and, when I have them, a reference image or two for the look. It reads the live design file first: the component library, the tokens, how the existing screens are built. Then it proposes a plan, which components it will reuse, which new component it thinks the system needs and why, how the screen stacks top to bottom, and waits.&lt;/p&gt;

&lt;p&gt;Only after my OK does it draw. Everything it draws is bound to tokens, and new components land in the library, documented like their neighbours. Reference images are for direction only; the colors and fonts stay Kurvenheld's.&lt;/p&gt;

&lt;h3&gt;
  
  
  kurvenheld-screen-update
&lt;/h3&gt;

&lt;p&gt;The review-feedback skill. Input is a text brief: "the sheet should get a close notch like the one on Discover", "make the back button icon-only". It finds the exact element in the file and decides the level of the change: the component master, so it propagates everywhere; this one instance; or inline. Then it lists every screen the change will touch, including the library's showcase, and waits for my go. After the edit it checks that the library still matches the screens.&lt;/p&gt;

&lt;p&gt;The whole skill is about blast radius. A change that fixes one screen and quietly breaks three others is worse than no change.&lt;/p&gt;

&lt;h3&gt;
  
  
  kurvenheld-screen-sync
&lt;/h3&gt;

&lt;p&gt;The reverse direction. Input is a screenshot of the implemented app. The skill makes the design file match what shipped, a sheet that never got designed, a screen that shipped differently, but builds it with the system's own components and tokens.&lt;/p&gt;

&lt;p&gt;When the app and the design system disagree, say a spacing that sits off the token scale or a hand-built element where a component exists, it doesn't decide. It lists the deviation with options and asks me. The app might be right and the system should evolve, or the app might be wrong and the implementation needs a fix. A screenshot can't tell you which.&lt;/p&gt;

&lt;h3&gt;
  
  
  kurvenheld-screen-implement
&lt;/h3&gt;

&lt;p&gt;The Flutter skill. Input is a finished design cell and the screen it belongs to. It reads the design, the component map and the current code, including the dialogs and sheets the screen opens, where legacy UI likes to hide. Then it writes a plan: every design element mapped to a component, every behaviour of the old view that has to survive (loading and error states, guest gating, analytics events, dismissal rules), and the open questions a static design can't answer.&lt;/p&gt;

&lt;p&gt;I approve, the plan gets executed, and the result is walked against that must-survive list line by line. The skill stays in the view layer. Where the new UI needed deeper changes, it said so instead of improvising, and that became its own task.&lt;/p&gt;

&lt;h3&gt;
  
  
  kurvenheld-screen-verify
&lt;/h3&gt;

&lt;p&gt;The one that drives the app. Input is a screen name. It exports the design cell from pen.dev, connects to the running app through Marionette, taps its way to the screen, takes screenshots and compares element by element.&lt;/p&gt;

&lt;p&gt;Out comes a numbered list of deviations, each with a severity. Then it asks which ones to fix. Approved fixes go in via hot reload, screenshot, compare again.&lt;/p&gt;

&lt;p&gt;When it gets stuck, a login wall, missing test data, a native map it can't see, it hands over to me instead of trying the same tap a fifth time. And it keeps a file of navigation recipes, so the next run doesn't rediscover the tap path.&lt;/p&gt;

&lt;p&gt;A surprising share of the work in each skill went into when &lt;em&gt;not&lt;/em&gt; to trigger and when to hand off to a sibling. Five skills in one domain means five chances to pick the wrong one, which is exactly what the Skill Creator's description optimization is for.&lt;/p&gt;

&lt;h2&gt;
  
  
  What every skill has in common
&lt;/h2&gt;

&lt;p&gt;Five skills, one skeleton.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Read the live state, never memory.&lt;/strong&gt; Every run reads the design file, the token list and the code it's about to touch before it proposes anything. Node ids, component names, the current structure: all read fresh, because a design file that several sessions edit in parallel changes under you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plan, then stop.&lt;/strong&gt; Each skill produces a plan and waits for my explicit OK before it edits a node or a line of code. For design changes the plan says at which level the edit lands: component master, this instance, or inline. For Flutter it maps every design element to a component and lists every behaviour of the old view that has to survive. Getting the level wrong either leaks one screen's quirk into every screen or leaves the system inconsistent. The plan is where that gets caught, and catching it there is cheap.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design-system discipline as hard rules.&lt;/strong&gt; Tokens only for fonts, spacing, radius and colors, in the design file and in Flutter. Reuse an existing component before building a new one, promote recurring UI into the library, keep the library's showcase in sync with every change. No decoration nobody asked for.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reference files that learn.&lt;/strong&gt; Two skills carry a living file next to their SKILL.md. The implement skill's collects runtime pitfalls: app-shell facts, layout traps and theme bleed-throughs that passed the analyzer and code review and only showed up in the simulator. The verify skill's collects navigation recipes: tap paths, preconditions, quirks. Every run reads them first and appends what it learned. A lesson I paid for once, on one screen, is free on the next 27.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evals.&lt;/strong&gt; The skills were iterated with the Skill Creator's evals, prompts plus assertions, run as plan-only dry runs. The agent plans and stops, so a test never mutates the design file, and a rewrite of a skill gets checked against the same prompts as the version before it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://krolmic.dev/blog/subagents-vs-teams/" rel="noopener noreferrer"&gt;Expensive planning, cheap execution.&lt;/a&gt;&lt;/strong&gt; For the Flutter skill the approved plan is written to disk as a self-contained file: component mapping, must-survive behaviours, the runtime pitfalls that apply to this screen, the open decisions already resolved. Executing it can happen in a fresh session on a cheaper model. Planning is the quality-critical half. Executing a fully specified, approved plan is where a model downgrade is safe.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The setup: one skills folder, two agents, many sessions
&lt;/h2&gt;

&lt;p&gt;The skills live in &lt;code&gt;.agents/skills/&lt;/code&gt;. &lt;code&gt;.claude/skills/&lt;/code&gt; holds symlinks into that folder, so Claude Code and Codex read the same files, and a change in &lt;code&gt;.agents&lt;/code&gt; needs no second edit anywhere. &amp;lt;!-- TODO confirm: Codex reads .agents/skills directly --&amp;gt;&lt;/p&gt;

&lt;p&gt;Design work ran in Claude Code connected to the pen.dev MCP. In my experience Claude is the strongest model for design work by a clear margin; what GPT produced on the same canvas was not close.&lt;/p&gt;

&lt;p&gt;Implementation and verification ran in Claude Code and Codex, both connected to the pen.dev MCP (to read the cell being implemented and export it for comparison) and to the Marionette MCP (to drive the running app). I worked in several git worktrees at once: one session implementing a screen, another verifying the previous one, a third redesigning the next cell in pen.dev. The approval gates are what make this workable. A session waiting for my OK costs nothing while I'm reading another one's plan, and because the plans are complete, approving one takes a minute, not a context switch.&lt;/p&gt;

&lt;p&gt;The stack, if you want to reproduce it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://pen.dev" rel="noopener noreferrer"&gt;pen.dev&lt;/a&gt; with its MCP server, &lt;code&gt;.pen&lt;/code&gt; file in the repo&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://claude.ai/code" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt; and &lt;a href="https://openai.com/codex/" rel="noopener noreferrer"&gt;Codex&lt;/a&gt;, sharing one skills folder&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://marionette.leancode.co/" rel="noopener noreferrer"&gt;Marionette MCP&lt;/a&gt; by LeanCode, plus the &lt;code&gt;marionette_flutter&lt;/code&gt; binding in the app, debug builds only&lt;/li&gt;
&lt;li&gt;Anthropic's &lt;a href="https://github.com/anthropics/skills/blob/main/skills/skill-creator/SKILL.md" rel="noopener noreferrer"&gt;Skill Creator&lt;/a&gt; for writing and evaluating the skills&lt;/li&gt;
&lt;li&gt;git worktrees, one per parallel session&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Watching agents drive the simulator
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://marionette.leancode.co/" rel="noopener noreferrer"&gt;Marionette MCP&lt;/a&gt; by LeanCode is, in their words, "Playwright MCP, but for Flutter apps". The app gets a small binding in debug builds, the MCP server connects to the app's VM service, and from there an agent can list what's tappable on screen, tap, type, scroll, take screenshots and read the logs.&lt;/p&gt;

&lt;p&gt;The verify skill uses it to close the loop. It exports the design cell from pen.dev, drives the running app to the screen, screenshots it and compares element by element: is everything from the design there, is it the right component in the right variant, do spacing, color, typography and icons match. Out comes a numbered list of deviations, each with where it is, what the design says, what the app shows and a severity.&lt;/p&gt;

&lt;p&gt;Then it asks me which ones to fix. Approved fixes go in through hot reload, then screenshot and compare again.&lt;/p&gt;

&lt;p&gt;I'll admit this part was fun. An agent tapping its way through the app on my simulator, tab to detail screen to sheet, while I was already working on the next screen in another window. The first time it happened I just sat there and watched.&lt;/p&gt;

&lt;p&gt;What it catches is the class of problem that passes &lt;code&gt;flutter analyze&lt;/code&gt; and looks fine in a diff: a gap one token step off, a component in the wrong variant, a legacy element the redesign should have removed, an overflow that only shows up in the console. What it's told not to flag: real data where the design has placeholder content, device chrome, scroll position. And when it's blocked, by a login wall, missing test data or a native map it can't see through Flutter's semantics tree, it hands over to me instead of trying the same tap again. Two cheap rounds of "put the app on the Groups screen and say ready" beat one agent thrashing against something it can't observe.&lt;/p&gt;

&lt;h2&gt;
  
  
  Human in the loop, by design
&lt;/h2&gt;

&lt;p&gt;The automation changed the speed of the loop. It didn't change who's responsible for what ships.&lt;/p&gt;

&lt;p&gt;Four review layers stayed in place:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The approval gate in every skill.&lt;/strong&gt; Nothing gets drawn in pen.dev or written in Dart before I've read the plan. A plan is a page, not a diff, and reading it is where I catch the wrong component level, the dropped behaviour, the open question the skill correctly refused to guess at. Some of those questions a static design can't answer at all, like what Apply and Reset do in a filter sheet when nothing changed. A person decides those, at plan time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design reviews with blindwerk.&lt;/strong&gt; After each batch of screens in pen.dev the agency reviewed. Their feedback went back in through the update skill, one plan per change, each stating which other screens it would touch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code reviews by blindwerk's developers.&lt;/strong&gt; Every work item went through review like any other PR in the project. The agents' code had to meet the coding standards, not the other way round.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;My own check before release.&lt;/strong&gt; In the simulator and in the code. You still have to understand the code the agents produce, confirm it matches the standards, and look for what they missed.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The result
&lt;/h2&gt;

&lt;p&gt;The redesigned Kurvenheld is live: &lt;a href="https://apps.apple.com/app/id1102821296" rel="noopener noreferrer"&gt;App Store&lt;/a&gt; · &lt;a href="https://play.google.com/store/apps/details?id=blindwerk.de.kurvenheld" rel="noopener noreferrer"&gt;Google Play&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Three phases, each under five working days: the proposals, the redesign of all 28 cells in pen.dev, the implementation of all screens in Flutter. Review rounds with blindwerk ran in between, so the calendar stretched further than fifteen days, but the effort didn't. Without the skills, the second and third phases alone would have blown past my whole original estimate.&lt;/p&gt;

&lt;p&gt;What changed in the process matters more to me than the hours. Every screen now has a design it was verified against. The design file still tells the truth about the app, because syncing it back is a skill and not a chore nobody does. And the next change to the app starts from a component library and a token set that design and code agree on.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Screen&lt;/th&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Discover&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftzxxt5rx2o7bfbr6reb1.webp" alt="Old Discover tab: a map of Badung, Bali with a 5 km search radius and a tour-count marker, above a sheet listing six tours for the location with a preview map, a photo, length, curves and elevation." width="780" height="1688"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feufwgnf7s97nxk0whhj9.webp" alt="New Discover tab: a search bar for Kabupaten Badung with a 5 km radius and a filter button over the map, above a sheet listing four tours for the location as photo cards with a difficulty badge, length, duration, a route preview, a seven-segment curve count and Like and Save buttons." width="780" height="1688"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ride&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq0ngqzb779i8opryxw19.webp" alt="Old Ride tab: a seven-segment curve counter at zero between yellow hazard stripes, distance and duration at zero, and Pause Tour and Finish Tour buttons." width="780" height="1688"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsppi0mdqwaw50mrbkeyx.webp" alt="New Ride tab: a dark panel with a seven-segment curve counter at 21, 4.05 km distance and 00:11 h duration over a tilted map with a yellow motorcycle marker, and Pause tour and Finish tour buttons above the tab bar." width="780" height="1688"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ranking&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvie1hcumaij15x1ml493.webp" alt="Old Ranking tab: a HighScore and UserScore toggle, a year picker, the signed-in rider at rank 193, and the top riders with avatars and seven-segment scores." width="780" height="1688"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8u86hlow8dznm04a3bpw.webp" alt="New Ranking tab: a Single tour and All tours toggle, a 2026 year picker, the signed-in rider pinned at rank 431 in a dark card, and the top riders in white cards with a yellow rank corner, an avatar and a seven-segment score." width="780" height="1688"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tour details&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffc6f402h6qpho32whi28.webp" alt="Old tour details screen: a black-and-white mountain-road header cut by a yellow diagonal, edit, bookmark and share buttons, the tour's statistics, a like row, a description and a route map." width="780" height="1688"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft2mheds2vdg6flcvv24z.webp" alt="New tour details screen: a full-bleed photo header with the tour name, the rider and date, an Easy badge and a seven-segment curve count, then a photo strip with an add button and a statistics card with curves, length, duration and ascent." width="780" height="1688"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;My Profile&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftxe239siliah54nr12sj.webp" alt="Old My Profile screen: a header photo with a yellow avatar, the rider's name, the 2026 rides, highscore and userscore counters, and Rides, Rankings, Trophies and Bookmarks tabs above a list of rides." width="780" height="1688"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv523fwwsyk8cou9eu08j.webp" alt="New My Profile screen: a sky photo header with a round avatar, the rider's name, a dark panel with the 2026 rides, highscore and userscore counters, a yellow trophies card with a 1 of 6 progress bar, and Rides, Rankings and Bookmarks tabs." width="780" height="1688"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Create challenge&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flvtteft7fvb6vdxiivz1.webp" alt="Old Create challenge screen, step 2 of 2: a blurred road header cut by a yellow diagonal, an optional award image, a Challenge target dropdown, a Winner award field, start and end dates, a Terms and Conditions checkbox, and Go back and Start buttons." width="780" height="1688"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0dj6xlaqxeif6xi0ahaz.webp" alt="New Create challenge wizard, step two of four: Pick a challenge target, with a list of targets such as Most Curves, Most Passes and Most Kilometers, each in a single tour or across all tours, and Back and Next buttons." width="780" height="1688"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you ride: Kurvenheld counts your curves, tracks your tours and lets your group challenge each other, &lt;a href="https://www.kurvenheld.de" rel="noopener noreferrer"&gt;kurvenheld.de&lt;/a&gt;. And if you need an app built or taken to its next version by a team that reviews this carefully, that's &lt;a href="https://www.blindwerk.de" rel="noopener noreferrer"&gt;blindwerk&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is pen.dev usable for a real production app redesign?&lt;/strong&gt; Yes. The constraint is discipline, not the tool: tokens only, a component library as the single source of truth, a plan before every edit. Enforced through skills, the &lt;code&gt;.pen&lt;/code&gt; file stayed a coherent system across 28 cells and a lot of parallel sessions. Without that discipline it turns into a folder of one-off mockups, which is also what happens in Figma.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why write skills instead of a long prompt I paste every time?&lt;/strong&gt; A pasted prompt carries rules. It doesn't carry the order of operations, the lessons from the last twenty runs, or tests. Skills carry all three, live in the repo next to the code and the design, and are read by Claude Code and Codex alike. When a run hits a new pitfall, the skill's reference file learns it. A prompt in a note doesn't.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why both Claude Code and Codex?&lt;/strong&gt; Claude for design, where the difference in output quality is large in my experience. For implementation and verification both work from the same skills, so the choice became one of capacity and cost: more parallel worktrees, and cheaper models executing plans I'd already approved.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you verify that a Flutter screen matches its design?&lt;/strong&gt; Drive the running app with the Marionette MCP, screenshot the screen, and compare it element by element against the exported design cell: presence, component and variant, spacing in token steps, color, typography, icons. Report deviations with a severity, fix only what a human approves, hot reload, compare again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does this replace the agency or the designer?&lt;/strong&gt; No. The decisions that make a redesign good were made by people, slowly, in Phase 1, and blindwerk reviewed every batch of designs and every code change after it. What the skills replaced is the repetitive translation between a decided design and the code, the part nobody should do by hand 28 times.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How long did the whole redesign take?&lt;/strong&gt; Each of the three phases took under five working days: proposals, redesign of all screens, implementation of all screens. Review rounds with blindwerk ran in between.&lt;/p&gt;

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

&lt;p&gt;The skills are specific to Kurvenheld on purpose. They know its design file, its component library and its codebase, and they'd be useless anywhere else. The pattern isn't specific at all: one skill per direction of truth, a plan-first gate in each, reference files that collect the runtime lessons, and verification that drives the real app instead of trusting the diff. Next time I'd set that up before the first screen, not after the estimate breaks.&lt;/p&gt;

&lt;p&gt;If you're planning a redesign of a Flutter app, or want this kind of design-to-code loop with pen.dev and Claude Code set up for your team, &lt;a href="https://krolmic.dev/contact" rel="noopener noreferrer"&gt;get in touch&lt;/a&gt;. It's the work I do.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>ai</category>
      <category>claude</category>
      <category>design</category>
    </item>
    <item>
      <title>Claude Code Subagents vs Agent Teams: A Better Default for Sequential Workflows</title>
      <dc:creator>Michał Król</dc:creator>
      <pubDate>Wed, 11 Nov 2026 07:14:43 +0000</pubDate>
      <link>https://dev.to/krolmic/claude-code-subagents-vs-agent-teams-a-better-default-for-sequential-workflows-10of</link>
      <guid>https://dev.to/krolmic/claude-code-subagents-vs-agent-teams-a-better-default-for-sequential-workflows-10of</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Subagents&lt;/strong&gt; (&lt;code&gt;.claude/agents/*.md&lt;/code&gt;) define a role: tools, model, system prompt, skills.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agent teams&lt;/strong&gt; are a communication group of named, still-running agents that can &lt;code&gt;SendMessage&lt;/code&gt; each other while both are alive.&lt;/li&gt;
&lt;li&gt;They're orthogonal primitives, not alternatives. A team uses subagents as the role each member plays; subagents work fine without a team.&lt;/li&gt;
&lt;li&gt;For a sequential plan → approve → implement workflow, main Claude already orchestrates and shuttles output between agents — there's no live back-and-forth, so a team is overhead.&lt;/li&gt;
&lt;li&gt;This post shows the two custom subagents (&lt;code&gt;planner.md&lt;/code&gt;, &lt;code&gt;implementer.md&lt;/code&gt;) and a &lt;code&gt;/task&lt;/code&gt; slash command I use instead — and how I run them automatically inside a GitHub Action for a client project.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is a custom subagent in Claude Code?
&lt;/h2&gt;

&lt;p&gt;A custom subagent in Claude Code is a Markdown file under &lt;code&gt;.claude/agents/&lt;/code&gt; that defines a role: which tools the agent can call, which model it runs on, its system prompt, and which skills it has access to. Main Claude can spawn it as a child task, hand it work, and read its final output back into the parent context.&lt;/p&gt;

&lt;p&gt;Subagents are personas. Each invocation gets a fresh context, scoped by the role you defined. They don't share state with each other and they don't talk to each other.&lt;/p&gt;

&lt;h2&gt;
  
  
  The misconception: teams are not an upgrade of subagents
&lt;/h2&gt;

&lt;p&gt;This is the bit I got wrong for months.&lt;/p&gt;

&lt;p&gt;I'd been treating "agent teams" and "custom subagents" as two ways to do the same thing. They aren't. They're orthogonal primitives.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Subagent&lt;/strong&gt; = a role definition (tools, model, prompt, skills). A persona.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Team&lt;/strong&gt; = a communication group of named, still-running agents that can &lt;code&gt;SendMessage&lt;/code&gt; each other directly while both are alive. The team is the &lt;em&gt;runtime&lt;/em&gt; that lets multiple personas talk in real time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A team uses subagents as the role each member plays. Subagents work fine without ever being in a team.&lt;/p&gt;

&lt;p&gt;The decision rule that finally clicked for me: &lt;strong&gt;reach for a team only when agents need to converse while both are alive&lt;/strong&gt;. If your workflow is sequential — agent A produces output, you (or main Claude) approve it, then agent B starts — you don't need a team. Main Claude is already the orchestrator. It can spawn one subagent, read the output, then spawn the next.&lt;/p&gt;

&lt;h2&gt;
  
  
  My old approach: spawning a team for every multi-agent task
&lt;/h2&gt;

&lt;p&gt;Whenever a task felt like it needed more than one agent, I'd send Claude something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Create an agent team for the following task:

Before creating an agent team ask me questions if anything is unclear.

Spawn two teammates:

1. Planner (name: "planner")
   - Model: Opus
   - Mode: Default
   - Role: Analyze the codebase and produce a detailed implementation plan with file-level changes. Flag ambiguities or risks. Output the plan as a structured message.

2. Implementer (name: "implementer")
   - Model: Sonnet
   - Mode: Default
   - Role: Implement the approved plan step by step. After 2 failed fix attempts on the same issue, report the blocker to the lead.

Coordination:
- Create tasks with dependencies: implementer is blocked until planner's
  plan is approved.
- The planner's plan requires approval from both you (the lead) and me
  before the implementer starts.

Figma:
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This worked. It also did three things I didn't actually need:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Held two agents alive in parallel when only one was active at a time.&lt;/li&gt;
&lt;li&gt;Re-defined the planner and implementer roles from scratch in every prompt, so the role definitions drifted between sessions.&lt;/li&gt;
&lt;li&gt;Burned coordination overhead on a workflow that was already strictly sequential.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The role definitions weren't version-controlled. The skill list wasn't tied to the agent. The whole thing lived in my prompt history.&lt;/p&gt;

&lt;h2&gt;
  
  
  My new approach: two custom subagents + a /task command
&lt;/h2&gt;

&lt;p&gt;Same workflow, expressed as two &lt;code&gt;.claude/agents/*.md&lt;/code&gt; files and a &lt;code&gt;/task&lt;/code&gt; slash command that orchestrates them. The role definitions live in the repo, get version-controlled, and carry their tool and skill lists with them.&lt;/p&gt;

&lt;h3&gt;
  
  
  planner.md
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;---
name: planner
description: "Analyzes the codebase and produces a detailed file-level implementation plan for a given task. Flags ambiguities and risks."
model: opus
color: pink
tools: Read, Glob, Grep, Bash, WebFetch, WebSearch, Skill, TaskCreate, TaskGet, mcp__figma__*
skills: flutter-apply-architecture-best-practices, flutter-build-responsive-layout, flutter-fix-layout-issues, flutter-implement-json-serialization, flutter-use-http-package, flutter-add-widget-test, flutter-accessibility-audit
---

You are the Planner. Your job is to produce a detailed, file-level implementation plan for given task — nothing more.

&lt;span class="gu"&gt;## What you do
&lt;/span&gt;
1. &lt;span class="gs"&gt;**If the task contains Figma links, fetch the design first — before anything else.**&lt;/span&gt; Extract every relevant design detail: layout, spacing, colors, typography, component structure, text content (labels, button text, headings, body copy), icons, images, and interactive states. Do not draft the plan or list open questions until the design has been fully read — many "questions" answer themselves once you see the file.
2. Read the relevant existing code so the plan is grounded in the real codebase, not assumptions.
3. Produce a structured plan covering:
   &lt;span class="k"&gt;- &lt;/span&gt;&lt;span class="gs"&gt;**Goal**&lt;/span&gt;: one-paragraph restatement of the task.
   &lt;span class="k"&gt;- &lt;/span&gt;&lt;span class="gs"&gt;**Files to change**&lt;/span&gt;: every file you expect to touch, listed at the function/class/method level with the specific change and the reason.
   &lt;span class="k"&gt;- &lt;/span&gt;&lt;span class="gs"&gt;**Files to add**&lt;/span&gt;: new files with their purpose and approximate shape (key classes, public API).
   &lt;span class="k"&gt;- &lt;/span&gt;&lt;span class="gs"&gt;**Test plan**&lt;/span&gt;: which tests to add or update.
   &lt;span class="k"&gt;- &lt;/span&gt;&lt;span class="gs"&gt;**Risks &amp;amp; ambiguities**&lt;/span&gt;: anything that could go wrong.
   &lt;span class="k"&gt;- &lt;/span&gt;&lt;span class="gs"&gt;**Open questions for the lead**&lt;/span&gt;: things that must be resolved before the implementer starts.
4. Be honest about uncertainty. If you are unsure, list it as an ambiguity with options — do not guess.

&lt;span class="gu"&gt;## What you do NOT do
&lt;/span&gt;
&lt;span class="k"&gt;- &lt;/span&gt;Do not modify files. You have no Edit/Write tools by design.
&lt;span class="k"&gt;- &lt;/span&gt;Do not implement the work. Your output is the plan only.
&lt;span class="k"&gt;- &lt;/span&gt;Do not pad the plan with restatements of project conventions the lead already knows. Focus on what is specific to this task.

&lt;span class="gu"&gt;## Output format
&lt;/span&gt;
Return one structured message in this shape:

&lt;span class="gu"&gt;# Plan: &amp;lt;task title&amp;gt;
&lt;/span&gt;
&lt;span class="gu"&gt;## Goal
&lt;/span&gt;
&lt;span class="gu"&gt;## Files to change
&lt;/span&gt;&lt;span class="k"&gt;- &lt;/span&gt;&lt;span class="sb"&gt;`path/to/file.dart`&lt;/span&gt;
  &lt;span class="k"&gt;- &lt;/span&gt;&lt;span class="sb"&gt;`ClassName.methodName`&lt;/span&gt;: &amp;lt;what changes and why&amp;gt;

&lt;span class="gu"&gt;## Files to add
&lt;/span&gt;&lt;span class="k"&gt;- &lt;/span&gt;&lt;span class="sb"&gt;`path/to/new_file.dart`&lt;/span&gt;: &amp;lt;purpose, key classes/functions&amp;gt;

&lt;span class="gu"&gt;## Test plan
&lt;/span&gt;&lt;span class="k"&gt;- &lt;/span&gt;...

&lt;span class="gu"&gt;## Risks &amp;amp; ambiguities
&lt;/span&gt;&lt;span class="k"&gt;- &lt;/span&gt;...

&lt;span class="gu"&gt;## Open questions for the lead
&lt;/span&gt;&lt;span class="k"&gt;- &lt;/span&gt;...

End your message with the literal line &lt;span class="gs"&gt;**`Plan ready for approval.`**&lt;/span&gt; so the lead knows to gate the implementer on it.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few things worth calling out about this file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The planner has no &lt;code&gt;Edit&lt;/code&gt; or &lt;code&gt;Write&lt;/code&gt; tool.&lt;/strong&gt; That's intentional — you cannot accidentally let the planner start coding. The role boundary is enforced by the tool list, not just by the prompt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skills are declared explicitly in &lt;code&gt;skills:&lt;/code&gt;.&lt;/strong&gt; Subagents don't automatically inherit the project's skills — you have to list them in the agent's frontmatter. (Built-in agents like Explorer / Plan / Verify can't access skills at all.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;color: pink&lt;/code&gt;.&lt;/strong&gt; Pink is one of my favorite colors and the planner header pops in the terminal output. Genuine question for anyone reading: what color is your planner?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  implementer.md
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;---
name: implementer
description: Implements a plan step by step.
model: sonnet
tools: Read, Write, Edit, Glob, Grep, Bash, WebFetch, WebSearch, Skill, TaskCreate, TaskGet, TaskUpdate, TaskList, mcp__figma__*
skills: flutter-apply-architecture-best-practices, flutter-build-responsive-layout, flutter-fix-layout-issues, flutter-implement-json-serialization, flutter-use-http-package, flutter-add-widget-test, flutter-accessibility-audit
---

Your key responsibility is to implement the given plan.

&lt;span class="gu"&gt;## Inputs you expect
&lt;/span&gt;
&lt;span class="k"&gt;- &lt;/span&gt;Implementation plan
&lt;span class="k"&gt;- &lt;/span&gt;Any modifications the lead and user agreed on during plan approval

&lt;span class="gu"&gt;## What you do
&lt;/span&gt;
Work through the plan step by step. Treat each "Files to change" / "Files to add" entry as a discrete unit of work.

&lt;span class="gu"&gt;## Blocker rule
&lt;/span&gt;
If the same issue fails twice after you tried to fix it, &lt;span class="gs"&gt;**stop and report**&lt;/span&gt;. Send a single message to the lead with:

&lt;span class="k"&gt;- &lt;/span&gt;What you were trying to do.
&lt;span class="k"&gt;- &lt;/span&gt;The two attempts you made and why each failed.
&lt;span class="k"&gt;- &lt;/span&gt;Your best hypothesis for the root cause.
&lt;span class="k"&gt;- &lt;/span&gt;What you would try next, or what input you need from the lead.

Do not loop on a third attempt. The lead decides whether to redirect, re-plan, or escalate to the user.

&lt;span class="gu"&gt;## Reporting back
&lt;/span&gt;
When the plan is fully implemented:

&lt;span class="k"&gt;- &lt;/span&gt;Summarize what changed (files + one-line per change).
&lt;span class="k"&gt;- &lt;/span&gt;List the verification checks you ran and their outcomes.
&lt;span class="k"&gt;- &lt;/span&gt;Note anything you intentionally deferred and why.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two details that matter here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The blocker rule lives in the implementer's prompt, not the orchestrator's.&lt;/strong&gt; Two failed fix attempts on the same issue → stop and report. No third try without input from the lead. This used to live in my team-spawning prompt and would silently drop out whenever I rewrote the prompt. Now it's pinned to the role.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The implementer runs on Sonnet.&lt;/strong&gt; Most of what an implementer does — applying a plan that's already been thought through — does not need Opus. Opus is reserved for the planner where actual reasoning happens.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  /task command
&lt;/h3&gt;

&lt;p&gt;For interactive use, you could just run main Claude and ask it to use the planner subagent first, then the implementer. That works, but it's repetitive. So I wrapped the orchestration in a slash command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;---
description: Run a workflow with planner and implementer subagents for a task
argument-hint: [--auto] &amp;lt;task description&amp;gt;
---

Run the workflow described below — using the &lt;span class="sb"&gt;`planner`&lt;/span&gt; and &lt;span class="sb"&gt;`implementer`&lt;/span&gt; subagents — for the following task:

$ARGUMENTS

&lt;span class="gu"&gt;## Mode
&lt;/span&gt;
&lt;span class="k"&gt;- &lt;/span&gt;&lt;span class="gs"&gt;**Interactive (default)**&lt;/span&gt;: analyze code related to the task ask clarifying questions if anything is unclear, and require my approval of the plan before implementation.
&lt;span class="k"&gt;- &lt;/span&gt;&lt;span class="gs"&gt;**Automated**&lt;/span&gt;: if the message above contains &lt;span class="sb"&gt;`--auto`&lt;/span&gt;, skip clarifying questions and skip my approval gate. Strip the &lt;span class="sb"&gt;`--auto`&lt;/span&gt; token from the task before passing it to the planner.

&lt;span class="gu"&gt;## Workflow
&lt;/span&gt;
1. &lt;span class="gs"&gt;**Clarify**&lt;/span&gt; — interactive mode only. If the task is unambiguous, skip to step 2. Otherwise ask me clarifying questions before spawning anything.

2. &lt;span class="gs"&gt;**Plan**&lt;/span&gt; — spawn the &lt;span class="sb"&gt;`planner`&lt;/span&gt; subagent with the task. Wait for the plan.

3. &lt;span class="gs"&gt;**Approve**&lt;/span&gt;
   &lt;span class="k"&gt;- &lt;/span&gt;Interactive mode: present the plan to me. Both you and I must approve before implementation. If either of us has changes, send them back to the planner.
   &lt;span class="k"&gt;- &lt;/span&gt;Automated mode: review the plan yourself. If it has critical issues (architectural conflicts, missing prerequisites, contradictions with &lt;span class="sb"&gt;`CLAUDE.md`&lt;/span&gt;), send it back to the planner with feedback. Otherwise approve and proceed.

4. &lt;span class="gs"&gt;**Implement**&lt;/span&gt; — spawn the &lt;span class="sb"&gt;`implementer`&lt;/span&gt; subagent with the approved plan. The implementer is blocked until approval.

5. &lt;span class="gs"&gt;**Blockers**&lt;/span&gt; — if the implementer reports a blocker after 2 failed fix attempts on the same issue:
   &lt;span class="k"&gt;- &lt;/span&gt;Interactive mode: surface it to me with the implementer's hypothesis and options. Do not loop on a third attempt without my input.
   &lt;span class="k"&gt;- &lt;/span&gt;Automated mode: halt the workflow and report the blocker with full context. Do not retry.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Interactive (default)&lt;/strong&gt; — clarify if needed, plan, present plan, wait for human approval, implement, surface blockers to me.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automated (&lt;code&gt;--auto&lt;/code&gt;)&lt;/strong&gt; — skip the interview and the human approval gate. Use this only when the input task is well-refined. (You can — and should — write a separate skill that enforces the refinement standard before &lt;code&gt;--auto&lt;/code&gt; ever runs.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;--auto&lt;/code&gt; mode is what makes the command usable inside CI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-world example: a GitHub Action for Aparkado
&lt;/h2&gt;

&lt;p&gt;For Aparkado (the team behind LKW.APP), I run this as part of an end-to-end automation:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A team member adds an &lt;code&gt;@automation-claude&lt;/code&gt; comment on a Linear issue labeled &lt;code&gt;App&lt;/code&gt; + &lt;code&gt;Automation&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A Make.com scenario calls GPT to validate the issue against the project's Definition of Ready and posts the JSON result (confidence score + comments) back to Linear. If the confidence score clears the threshold, Make.com creates a branch from &lt;code&gt;develop&lt;/code&gt;, commits a &lt;code&gt;task.md&lt;/code&gt; containing the refined task, and opens a PR.&lt;/li&gt;
&lt;li&gt;A GitHub Action triggers on PR creation. It runs Claude Code, which executes &lt;code&gt;/task --auto&lt;/code&gt; against the contents of &lt;code&gt;task.md&lt;/code&gt;. The two subagents do the work — plan, then implement — commit, push, and remove &lt;code&gt;task.md&lt;/code&gt; in a final cleanup commit.&lt;/li&gt;
&lt;li&gt;A human reviews the PR. We deliberately keep this step for knowledge sharing, not because the code needs it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The whole point of this pipeline is that the &lt;em&gt;expensive&lt;/em&gt; part — refining the task to a state Claude can implement well — happens &lt;em&gt;before&lt;/em&gt; the agents run. The DoR check enforces it. By the time &lt;code&gt;/task --auto&lt;/code&gt; fires, the input is good enough that no clarifying questions are needed.&lt;/p&gt;

&lt;p&gt;If I'd built this same pipeline with agent teams, every PR would have been spawning a runtime communication group, paying the coordination tax, and re-defining the planner and implementer roles from scratch in every CI run. With custom subagents, the roles are committed to the repo and the pipeline is just &lt;code&gt;claude --slash-command "/task --auto $TASK"&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Are subagents and agent teams interchangeable?&lt;/strong&gt;&lt;br&gt;
No. Subagents define a role; teams define a runtime communication group. A team uses subagents as the role of each member, but subagents work without a team.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When should I actually use an agent team?&lt;/strong&gt;&lt;br&gt;
When you need agents to converse while both are alive — a debate, a back-and-forth code review, a long-running pair-programming session. If your workflow is sequential, main Claude is already the orchestrator and you don't need a team.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why does the planner have no Edit or Write tools?&lt;/strong&gt;&lt;br&gt;
Role separation is enforced by the tool list, not just by the prompt. Removing those tools makes it physically impossible for the planner to start implementing the task.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do subagents inherit the project's skills automatically?&lt;/strong&gt;&lt;br&gt;
No. You have to list each skill explicitly in the agent's &lt;code&gt;skills:&lt;/code&gt; frontmatter. Built-in agents (Explorer, Plan, Verify) can't access skills at all — only custom subagents in &lt;code&gt;.claude/agents/&lt;/code&gt; can.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I run /task in CI without a human in the loop?&lt;/strong&gt;&lt;br&gt;
Yes — &lt;code&gt;/task --auto&lt;/code&gt; skips the clarifying interview and the approval gate. Only do this when the input task is well-refined; otherwise the planner has nothing solid to ground its plan on. A well-defined Definition of Ready, enforced before the action runs, is what makes this safe.&lt;/p&gt;

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

&lt;p&gt;This post focused on subagents. The same Anthropic Skills course also reshaped how I think about skill descriptions, the SKILL.md structure, the priority order between enterprise / personal / project / plugin skills, and when to reach for a hook or slash command instead of a skill. I'll write those up next.&lt;/p&gt;

&lt;p&gt;If this kind of orchestration is something you're building into a client project and you want a second pair of eyes on it, &lt;a href="https://krolmic.dev/contact" rel="noopener noreferrer"&gt;get in touch&lt;/a&gt; — it's the work I do.&lt;/p&gt;

</description>
      <category>claude</category>
      <category>ai</category>
      <category>softwaredevelopment</category>
      <category>githubactions</category>
    </item>
  </channel>
</rss>
