<?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: Alex Shev</title>
    <description>The latest articles on DEV Community by Alex Shev (@alexshev).</description>
    <link>https://dev.to/alexshev</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%2F3812101%2Fa5dfb3f9-d006-41a1-a868-995b7f219269.png</url>
      <title>DEV Community: Alex Shev</title>
      <link>https://dev.to/alexshev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alexshev"/>
    <language>en</language>
    <item>
      <title>Stop Testing APIs by Hand. Give Your AI Agent a Bruno Workflow.</title>
      <dc:creator>Alex Shev</dc:creator>
      <pubDate>Wed, 29 Jul 2026 23:25:57 +0000</pubDate>
      <link>https://dev.to/alexshev/stop-testing-apis-by-hand-give-your-ai-agent-a-bruno-workflow-3gk2</link>
      <guid>https://dev.to/alexshev/stop-testing-apis-by-hand-give-your-ai-agent-a-bruno-workflow-3gk2</guid>
      <description>&lt;p&gt;Most API testing workflows break in a boring way.&lt;/p&gt;

&lt;p&gt;Not because the team does not care about testing.&lt;/p&gt;

&lt;p&gt;Not because nobody knows how to send a request.&lt;/p&gt;

&lt;p&gt;Because the API workflow lives in too many places at once.&lt;/p&gt;

&lt;p&gt;One developer has a Postman collection.&lt;br&gt;
Another has a few curl commands in shell history.&lt;br&gt;
The backend repo has environment variables in &lt;code&gt;.env.example&lt;/code&gt;.&lt;br&gt;
CI has a smoke test that only checks one endpoint.&lt;br&gt;
The docs say one thing.&lt;br&gt;
The staging API behaves slightly differently.&lt;/p&gt;

&lt;p&gt;Then an AI coding agent enters the repo and gets asked:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Can you check this API flow?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent can read code.&lt;br&gt;
It can write tests.&lt;br&gt;
It can generate curl commands.&lt;br&gt;
It can explain HTTP status codes.&lt;/p&gt;

&lt;p&gt;But it still has the same problem a new human has.&lt;/p&gt;

&lt;p&gt;Where is the API workflow?&lt;/p&gt;

&lt;p&gt;If the answer is "somewhere in a GUI tool, someone's local history, and a few scattered docs," the agent has to reconstruct the whole thing from scratch.&lt;/p&gt;

&lt;p&gt;That is not a tool problem.&lt;/p&gt;

&lt;p&gt;That is a workflow packaging problem.&lt;/p&gt;


&lt;h2&gt;
  
  
  API collections should live near the code
&lt;/h2&gt;

&lt;p&gt;This is why I like Bruno.&lt;/p&gt;

&lt;p&gt;Bruno is an open-source API client that stores collections as plain text files in your Git repository.&lt;/p&gt;

&lt;p&gt;That detail matters more than the UI.&lt;/p&gt;

&lt;p&gt;If your API collection lives next to the application code, it becomes part of the engineering system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;request changes show up in pull requests&lt;/li&gt;
&lt;li&gt;environment files can be reviewed&lt;/li&gt;
&lt;li&gt;auth flows can be documented as runnable requests&lt;/li&gt;
&lt;li&gt;test assertions can live with the request that needs them&lt;/li&gt;
&lt;li&gt;CI can run the same collection humans use locally&lt;/li&gt;
&lt;li&gt;new team members can learn the API by running the collection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The collection is not a private artifact hidden in a synced workspace.&lt;/p&gt;

&lt;p&gt;It is a repo artifact.&lt;/p&gt;

&lt;p&gt;That changes what an AI agent can do with it.&lt;/p&gt;


&lt;h2&gt;
  
  
  The real unit is not a request
&lt;/h2&gt;

&lt;p&gt;A single API request is easy.&lt;/p&gt;

&lt;p&gt;The useful workflow is usually a sequence:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Login.&lt;/li&gt;
&lt;li&gt;Save the token.&lt;/li&gt;
&lt;li&gt;Create a resource.&lt;/li&gt;
&lt;li&gt;Read it back.&lt;/li&gt;
&lt;li&gt;Update it.&lt;/li&gt;
&lt;li&gt;Verify the response shape.&lt;/li&gt;
&lt;li&gt;Clean up or test the failure path.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When developers test this manually, they often remember the sequence in their head.&lt;/p&gt;

&lt;p&gt;That works until the API changes.&lt;/p&gt;

&lt;p&gt;It works until staging has different data.&lt;/p&gt;

&lt;p&gt;It works until someone else needs to debug the same flow.&lt;/p&gt;

&lt;p&gt;It works until an agent has to run it and cannot rely on tribal memory.&lt;/p&gt;

&lt;p&gt;The important thing to encode is not:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Send a POST request.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;This is the auth flow.
These variables move from one request to the next.
These assertions prove the contract still works.
This command runs the flow in CI.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is where Bruno's file-based model becomes useful.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;.bru&lt;/code&gt; request can contain the request metadata, headers, body, scripts, and tests in a human-readable format.&lt;/p&gt;

&lt;p&gt;An environment file can define &lt;code&gt;baseUrl&lt;/code&gt;, test users, and secret placeholders.&lt;/p&gt;

&lt;p&gt;Post-response scripts can save values for later requests.&lt;/p&gt;

&lt;p&gt;The CLI can run the collection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bru run &lt;span class="nt"&gt;--env&lt;/span&gt; staging
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or a folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bru run auth/ &lt;span class="nt"&gt;--env&lt;/span&gt; dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or output CI-friendly results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bru run &lt;span class="nt"&gt;--env&lt;/span&gt; dev &lt;span class="nt"&gt;--output&lt;/span&gt; results.xml &lt;span class="nt"&gt;--format&lt;/span&gt; junit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is a much better artifact for an agent than a vague instruction like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Test the API.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What an AI agent should not improvise
&lt;/h2&gt;

&lt;p&gt;I do not want an agent inventing an API testing workflow every time.&lt;/p&gt;

&lt;p&gt;That is how you get impressive-looking activity and weak verification.&lt;/p&gt;

&lt;p&gt;The agent might:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;hit the happy path only&lt;/li&gt;
&lt;li&gt;test against the wrong environment&lt;/li&gt;
&lt;li&gt;forget auth state&lt;/li&gt;
&lt;li&gt;use fake data that bypasses the real bug&lt;/li&gt;
&lt;li&gt;skip assertions and only report that the request returned something&lt;/li&gt;
&lt;li&gt;paste a curl command that nobody ever runs again&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of those failures look dramatic.&lt;/p&gt;

&lt;p&gt;They look like work.&lt;/p&gt;

&lt;p&gt;The agent says:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I tested the endpoint.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the team has no durable artifact, no diff, no reusable flow, and no CI hook.&lt;/p&gt;

&lt;p&gt;That is the wrong end state.&lt;/p&gt;

&lt;p&gt;For API work, I want the agent to leave behind something the repo can keep.&lt;/p&gt;




&lt;h2&gt;
  
  
  A better Bruno workflow for agents
&lt;/h2&gt;

&lt;p&gt;The workflow I would want from an AI coding agent looks like this.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Discover the API surface
&lt;/h3&gt;

&lt;p&gt;The agent should inspect routes, controllers, OpenAPI specs if they exist, existing tests, and any current API docs.&lt;/p&gt;

&lt;p&gt;The output should be a short map:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;auth endpoints&lt;/li&gt;
&lt;li&gt;core resources&lt;/li&gt;
&lt;li&gt;destructive actions&lt;/li&gt;
&lt;li&gt;environment assumptions&lt;/li&gt;
&lt;li&gt;test data requirements&lt;/li&gt;
&lt;li&gt;flows that need chained state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No collection changes yet.&lt;/p&gt;

&lt;p&gt;First understand the shape.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Create a Git-friendly collection structure
&lt;/h3&gt;

&lt;p&gt;The collection should mirror the API, not the agent's thought process.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;api-collection/
  bruno.json
  environments/
    dev.bru
    staging.bru
  auth/
    login.bru
    refresh-token.bru
  users/
    list-users.bru
    get-user.bru
    create-user.bru
  orders/
    create-order.bru
    process-refund.bru
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That structure is boring on purpose.&lt;/p&gt;

&lt;p&gt;People can navigate it.&lt;/p&gt;

&lt;p&gt;Agents can navigate it.&lt;/p&gt;

&lt;p&gt;Reviewers can diff it.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Encode variables and secrets correctly
&lt;/h3&gt;

&lt;p&gt;Environment files should carry normal config like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;baseUrl: http://localhost:3000
testEmail: test@example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Secrets should be marked as secrets and not committed as plain values.&lt;/p&gt;

&lt;p&gt;This is one of the places where an agent needs a rule, not vibes.&lt;/p&gt;

&lt;p&gt;If a tool can run requests, it can also leak credentials by accident.&lt;/p&gt;

&lt;p&gt;So the workflow has to define where config lives, which values can be committed, and what must stay local or injected by CI.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Chain requests deliberately
&lt;/h3&gt;

&lt;p&gt;Many real API tests are stateful.&lt;/p&gt;

&lt;p&gt;Login returns a token.&lt;/p&gt;

&lt;p&gt;Create user returns an ID.&lt;/p&gt;

&lt;p&gt;Create order depends on the user.&lt;/p&gt;

&lt;p&gt;Refund depends on the order.&lt;/p&gt;

&lt;p&gt;The agent should not fake those IDs when it can capture them from the real response.&lt;/p&gt;

&lt;p&gt;That is where post-response scripts are useful.&lt;/p&gt;

&lt;p&gt;The point is not clever scripting.&lt;/p&gt;

&lt;p&gt;The point is making the API flow executable instead of explanatory.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Put assertions next to the request
&lt;/h3&gt;

&lt;p&gt;A request without assertions is only a smoke signal.&lt;/p&gt;

&lt;p&gt;The agent should add tests for the contract that matters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;status code&lt;/li&gt;
&lt;li&gt;required fields&lt;/li&gt;
&lt;li&gt;expected types&lt;/li&gt;
&lt;li&gt;auth behavior&lt;/li&gt;
&lt;li&gt;error shape&lt;/li&gt;
&lt;li&gt;permission boundaries&lt;/li&gt;
&lt;li&gt;idempotency or retry behavior when relevant&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The test should answer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What would make this endpoint unsafe to ship?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Did the server return any JSON?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. Add a CI command
&lt;/h3&gt;

&lt;p&gt;The workflow is not done until there is a command the team can run again.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bru run &lt;span class="nt"&gt;--env&lt;/span&gt; staging
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bru run auth/ &lt;span class="nb"&gt;users&lt;/span&gt;/ &lt;span class="nt"&gt;--env&lt;/span&gt; ci &lt;span class="nt"&gt;--output&lt;/span&gt; results.xml &lt;span class="nt"&gt;--format&lt;/span&gt; junit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact command depends on the project.&lt;/p&gt;

&lt;p&gt;But the artifact should be clear enough that a developer, CI job, or future agent can repeat the same check.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where Terminal Skills fits
&lt;/h2&gt;

&lt;p&gt;This is exactly the kind of workflow that belongs in a skill.&lt;/p&gt;

&lt;p&gt;The Terminal Skills catalog has a &lt;code&gt;bruno&lt;/code&gt; skill for AI agents:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://terminalskills.io/skills/bruno" rel="noopener noreferrer"&gt;Bruno on Terminal Skills&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The useful part is not "the agent has heard of Bruno."&lt;/p&gt;

&lt;p&gt;That is not enough.&lt;/p&gt;

&lt;p&gt;The useful part is giving the agent an operating procedure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use Bruno as a Git-first API testing tool&lt;/li&gt;
&lt;li&gt;store collections as reviewable repo files&lt;/li&gt;
&lt;li&gt;organize requests by API structure&lt;/li&gt;
&lt;li&gt;use environment files for config&lt;/li&gt;
&lt;li&gt;keep secrets out of committed values&lt;/li&gt;
&lt;li&gt;write assertions in requests&lt;/li&gt;
&lt;li&gt;chain state between calls intentionally&lt;/li&gt;
&lt;li&gt;run collections through the Bruno CLI&lt;/li&gt;
&lt;li&gt;treat the collection as living API documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Install for Codex:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx terminal-skills &lt;span class="nb"&gt;install &lt;/span&gt;bruno &lt;span class="nt"&gt;--agent&lt;/span&gt; codex
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install for Gemini CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx terminal-skills &lt;span class="nb"&gt;install &lt;/span&gt;bruno &lt;span class="nt"&gt;--agent&lt;/span&gt; gemini
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install for Claude Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx terminal-skills &lt;span class="nb"&gt;install &lt;/span&gt;bruno
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The broader point is simple:&lt;/p&gt;

&lt;p&gt;If an agent is going to touch your API workflow, do not ask it to improvise testing.&lt;/p&gt;

&lt;p&gt;Give it a repeatable workflow it can follow, edit, run, and leave behind.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this matters for API teams
&lt;/h2&gt;

&lt;p&gt;API testing is one of those areas where AI can create false confidence quickly.&lt;/p&gt;

&lt;p&gt;An agent can generate a convincing explanation of an endpoint.&lt;/p&gt;

&lt;p&gt;It can generate sample requests.&lt;/p&gt;

&lt;p&gt;It can say the test passed.&lt;/p&gt;

&lt;p&gt;But unless the workflow leaves a durable artifact, the value disappears after the chat.&lt;/p&gt;

&lt;p&gt;The better outcome is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the Bruno collection was updated&lt;/li&gt;
&lt;li&gt;the change is visible in Git&lt;/li&gt;
&lt;li&gt;the request has assertions&lt;/li&gt;
&lt;li&gt;the environment is explicit&lt;/li&gt;
&lt;li&gt;the command can run locally&lt;/li&gt;
&lt;li&gt;CI can run it later&lt;/li&gt;
&lt;li&gt;the next agent does not need to rediscover the flow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the difference between assistance and operational memory.&lt;/p&gt;

&lt;p&gt;The agent did not just test the API.&lt;/p&gt;

&lt;p&gt;It improved how the team tests the API.&lt;/p&gt;




&lt;h2&gt;
  
  
  My practical checklist
&lt;/h2&gt;

&lt;p&gt;If I were reviewing an agent-generated Bruno workflow, I would ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does the collection live in the repo?&lt;/li&gt;
&lt;li&gt;Does the folder structure match the API shape?&lt;/li&gt;
&lt;li&gt;Are environments separated cleanly?&lt;/li&gt;
&lt;li&gt;Are secrets marked and excluded from committed values?&lt;/li&gt;
&lt;li&gt;Do important requests include assertions?&lt;/li&gt;
&lt;li&gt;Are auth tokens and IDs passed through real response state?&lt;/li&gt;
&lt;li&gt;Can the collection run from the CLI?&lt;/li&gt;
&lt;li&gt;Is there a CI-ready command?&lt;/li&gt;
&lt;li&gt;Would a new teammate understand the API faster after reading and running it?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the answer is yes, the agent left behind something useful.&lt;/p&gt;

&lt;p&gt;If the answer is no, it probably just tested by hand with extra steps.&lt;/p&gt;




&lt;h2&gt;
  
  
  The broader lesson
&lt;/h2&gt;

&lt;p&gt;AI agents are good at producing one-off work.&lt;/p&gt;

&lt;p&gt;Engineering teams need repeatable work.&lt;/p&gt;

&lt;p&gt;That is the gap skills are meant to close.&lt;/p&gt;

&lt;p&gt;For API testing, the difference is especially visible.&lt;/p&gt;

&lt;p&gt;Do you want the agent to send a request once?&lt;/p&gt;

&lt;p&gt;Or do you want it to build the API workflow your team can keep using?&lt;/p&gt;

&lt;p&gt;That is why Bruno is a good fit for Terminal Skills.&lt;/p&gt;

&lt;p&gt;It turns API testing into files, diffs, commands, and checks.&lt;/p&gt;

&lt;p&gt;And those are exactly the kinds of artifacts agents can use without asking everyone to trust a chat transcript.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: AI assistance was used to draft and edit this article.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>testing</category>
      <category>devtools</category>
      <category>ai</category>
    </item>
    <item>
      <title>I fixed an unbounded audio queue in a live translation server before it could take the process down</title>
      <dc:creator>Alex Shev</dc:creator>
      <pubDate>Wed, 15 Jul 2026 01:51:04 +0000</pubDate>
      <link>https://dev.to/alexshev/i-fixed-an-unbounded-audio-queue-in-a-live-translation-server-before-it-could-take-the-process-down-i6m</link>
      <guid>https://dev.to/alexshev/i-fixed-an-unbounded-audio-queue-in-a-live-translation-server-before-it-could-take-the-process-down-i6m</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/bugsmash"&gt;DEV's Summer Bug Smash: Clear the Lineup&lt;/a&gt; powered by &lt;a href="https://sentry.io/" rel="noopener noreferrer"&gt;Sentry&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Overview
&lt;/h2&gt;

&lt;p&gt;The project is a live speech translation app.&lt;/p&gt;

&lt;p&gt;A browser client captures microphone audio, converts it to 16 kHz PCM, and streams it to a NestJS server over Socket.IO. The server opens one WebSocket session to a local ML service, forwards the audio frames, and relays translated segments back to listeners.&lt;/p&gt;

&lt;p&gt;The important part for this bug: audio starts arriving from the browser before the ML WebSocket is guaranteed to be open.&lt;/p&gt;

&lt;p&gt;That is normal for realtime systems. The dangerous part was what happened when the ML service was unavailable, slow to handshake, or stuck behind a bad connection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug Fix or Performance Improvement
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;MlSession&lt;/code&gt; class buffered audio frames while waiting for the ML WebSocket to open:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;sendAudio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pcm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;closed&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pcm&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pcm&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;That looks harmless until you remember what the data is: raw PCM audio.&lt;/p&gt;

&lt;p&gt;At 16 kHz, mono, 16-bit PCM, the stream is roughly 32 KB per second per active speaker. If the ML WebSocket never opens, every &lt;code&gt;audio&lt;/code&gt; event keeps appending another &lt;code&gt;Buffer&lt;/code&gt; to &lt;code&gt;queue&lt;/code&gt;. A stalled ML service could quietly turn one active audio source into an unbounded memory growth path.&lt;/p&gt;

&lt;p&gt;The server did not have to be under heavy traffic for this to matter. One broadcaster with a stuck ML backend was enough to create an ever-growing in-memory queue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;I added an explicit cap for queued audio before the ML connection opens, tracked queued bytes, reset the counter once the connection opens, and released queued buffers on close/error.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MAX_QUEUED_AUDIO_BYTES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ML_MAX_QUEUED_AUDIO_BYTES&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;512&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1024&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;The send path now fails fast instead of buffering forever:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;sendAudio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pcm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;closed&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pcm&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queuedBytes&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;pcm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;byteLength&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;MAX_QUEUED_AUDIO_BYTES&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;finish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ML websocket audio queue overflow before connection opened&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&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="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pcm&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queuedBytes&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;pcm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;byteLength&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the socket opens, queued audio is flushed and the byte counter goes back to zero:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;open&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;config&lt;/span&gt;&lt;span class="dl"&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;config&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;open&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;for &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;buf&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queuedBytes&lt;/span&gt; &lt;span class="o"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Close/error paths also clear the queue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;closed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queuedBytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;finish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;closed&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;closed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queuedBytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onClose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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;h2&gt;
  
  
  My Improvements
&lt;/h2&gt;

&lt;p&gt;The fix changes the failure mode.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;ML service unavailable or stuck&lt;/li&gt;
&lt;li&gt;browser keeps streaming audio&lt;/li&gt;
&lt;li&gt;server queues every PCM frame&lt;/li&gt;
&lt;li&gt;memory grows until the process is restarted or killed&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;ML service unavailable or stuck&lt;/li&gt;
&lt;li&gt;server accepts only a bounded amount of pending audio&lt;/li&gt;
&lt;li&gt;session closes with a specific overflow error&lt;/li&gt;
&lt;li&gt;existing gateway cleanup runs and listeners get the normal ended signal&lt;/li&gt;
&lt;li&gt;memory is released immediately&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I kept the default cap at &lt;code&gt;512 KB&lt;/code&gt;, which is around 16 seconds of 16 kHz mono PCM audio. That is enough for normal connection delay but small enough to prevent a single stalled session from becoming a memory leak.&lt;/p&gt;

&lt;p&gt;The value is configurable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;ML_MAX_QUEUED_AUDIO_BYTES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1048576
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That lets production tune the buffer based on expected network conditions without changing code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verification
&lt;/h2&gt;

&lt;p&gt;The normal server build still passes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; live-translation-server@0.1.0 build
&amp;gt; tsc -p tsconfig.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also ran a smoke test that accepts the TCP connection but intentionally never completes the WebSocket handshake. Then I sent audio chunks into &lt;code&gt;MlSession&lt;/code&gt; with a small queue limit.&lt;/p&gt;

&lt;p&gt;Expected result: the session should close with the overflow error instead of keeping the buffers forever.&lt;/p&gt;

&lt;p&gt;Observed result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"closed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"errMessage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"ML websocket audio queue overflow before connection opened"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the behavior I wanted: when the ML backend is not actually ready to receive audio, the realtime server fails the session explicitly instead of becoming a quiet memory sink.&lt;/p&gt;

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

&lt;p&gt;Realtime systems make small buffers feel safe.&lt;/p&gt;

&lt;p&gt;This was not a dramatic bug in the happy path. The app worked when the ML WebSocket opened quickly. The bug lived in the waiting room between "the browser is already sending audio" and "the ML service is ready."&lt;/p&gt;

&lt;p&gt;That is exactly where production bugs like to hide: not in the main algorithm, but in the glue code that assumes the next component will be ready soon.&lt;/p&gt;

&lt;p&gt;The fix was not a bigger abstraction. It was a boundary:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;audio may wait briefly, but it may not wait forever.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That one rule turns an unbounded failure into a controlled one.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>bugsmash</category>
      <category>webdev</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Your AI App Does Not Need Ten Model Clients. It Needs a Gateway Workflow.</title>
      <dc:creator>Alex Shev</dc:creator>
      <pubDate>Tue, 14 Jul 2026 23:44:12 +0000</pubDate>
      <link>https://dev.to/alexshev/your-ai-app-does-not-need-ten-model-clients-it-needs-a-gateway-workflow-15il</link>
      <guid>https://dev.to/alexshev/your-ai-app-does-not-need-ten-model-clients-it-needs-a-gateway-workflow-15il</guid>
      <description>&lt;p&gt;Most AI apps start with one provider.&lt;/p&gt;

&lt;p&gt;That is usually fine.&lt;/p&gt;

&lt;p&gt;You add an OpenAI SDK call, pick a model, ship the feature, and move on.&lt;/p&gt;

&lt;p&gt;Then the product grows.&lt;/p&gt;

&lt;p&gt;One workflow needs a cheaper model. Another needs a stronger reasoning model. Another needs image or video generation. A customer wants data routed through a specific provider. A fallback model becomes necessary because the primary one is rate-limited during a launch.&lt;/p&gt;

&lt;p&gt;Suddenly, "just call the model" is not really the architecture anymore.&lt;/p&gt;

&lt;p&gt;The real problem is routing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The trap: provider logic spread across the app
&lt;/h2&gt;

&lt;p&gt;The messy version looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;support_summary&lt;/span&gt;&lt;span class="dl"&gt;"&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="nx"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;deep_research&lt;/span&gt;&lt;span class="dl"&gt;"&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="nx"&gt;anthropic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;image&lt;/span&gt;&lt;span class="dl"&gt;"&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="nx"&gt;imageProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&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;That works for a while.&lt;/p&gt;

&lt;p&gt;But as soon as the team needs fallbacks, model swaps, cost controls, or media endpoints, provider decisions start leaking into product code.&lt;/p&gt;

&lt;p&gt;Now the app has two problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;product logic&lt;/li&gt;
&lt;li&gt;model routing logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those should not be the same layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  A gateway is boring in the best way
&lt;/h2&gt;

&lt;p&gt;This is why I like the &lt;code&gt;routerbase-gateway&lt;/code&gt; pattern on Terminal Skills.&lt;/p&gt;

&lt;p&gt;The useful idea is not "one more AI provider."&lt;/p&gt;

&lt;p&gt;The useful idea is putting OpenAI-compatible calls, model IDs, fallback choices, streaming behavior, tool calling, JSON mode, and media generation behind one gateway layer.&lt;/p&gt;

&lt;p&gt;Instead of teaching every part of the app how to talk to every model provider, the application talks to one interface.&lt;/p&gt;

&lt;p&gt;The routing layer decides what happens behind it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;OpenAI&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;openai&lt;/span&gt;&lt;span class="dl"&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;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ROUTERBASE_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;baseURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.routerbase.com/v1&lt;/span&gt;&lt;span class="dl"&gt;"&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fast-support-summary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;messages&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="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;system&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Summarize the customer issue clearly.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;transcript&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application code stays boring.&lt;/p&gt;

&lt;p&gt;The routing policy can change without rewriting every feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters for agents
&lt;/h2&gt;

&lt;p&gt;An AI coding agent can wire up raw API calls.&lt;/p&gt;

&lt;p&gt;That is not the hard part.&lt;/p&gt;

&lt;p&gt;The hard part is getting the agent to make the same architectural decision the team would make:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;keep provider-specific logic out of product code&lt;/li&gt;
&lt;li&gt;use environment variables consistently&lt;/li&gt;
&lt;li&gt;keep model names configurable&lt;/li&gt;
&lt;li&gt;support fallbacks without scattering conditionals everywhere&lt;/li&gt;
&lt;li&gt;preserve streaming and JSON-mode behavior where the feature needs it&lt;/li&gt;
&lt;li&gt;avoid logging sensitive prompts or keys&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is exactly the kind of workflow that belongs in a skill.&lt;/p&gt;

&lt;p&gt;Not because the commands are complicated.&lt;/p&gt;

&lt;p&gt;Because the judgment should be repeatable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The skill version of the task
&lt;/h2&gt;

&lt;p&gt;Without a skill, the prompt tends to be vague:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Migrate this app to use RouterBase.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That leaves too many decisions open.&lt;/p&gt;

&lt;p&gt;With a workflow-oriented skill, the agent has a narrower job:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx terminal-skills &lt;span class="nb"&gt;install &lt;/span&gt;routerbase-gateway &lt;span class="nt"&gt;--agent&lt;/span&gt; codex
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the agent can follow a safer pattern:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Find existing OpenAI-compatible client calls.&lt;/li&gt;
&lt;li&gt;Move provider configuration into environment variables.&lt;/li&gt;
&lt;li&gt;Replace direct provider clients with the gateway base URL.&lt;/li&gt;
&lt;li&gt;Keep model IDs outside hard-coded feature logic where possible.&lt;/li&gt;
&lt;li&gt;Preserve streaming, tool calling, and structured-output behavior.&lt;/li&gt;
&lt;li&gt;Add a small verification path before claiming the migration worked.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That is much closer to production work than "switch the API key."&lt;/p&gt;

&lt;h2&gt;
  
  
  The real win is change management
&lt;/h2&gt;

&lt;p&gt;Model routing is not just an infra preference.&lt;/p&gt;

&lt;p&gt;It changes how product teams can operate.&lt;/p&gt;

&lt;p&gt;When the routing layer is explicit, the team can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;test cheaper models on low-risk tasks&lt;/li&gt;
&lt;li&gt;keep stronger models for high-value workflows&lt;/li&gt;
&lt;li&gt;add a fallback route for outages&lt;/li&gt;
&lt;li&gt;move media generation behind the same operational pattern&lt;/li&gt;
&lt;li&gt;compare providers without rewriting the feature&lt;/li&gt;
&lt;li&gt;keep provider churn away from product code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The application becomes less attached to one vendor.&lt;/p&gt;

&lt;p&gt;The team becomes more explicit about which model is used for which job.&lt;/p&gt;

&lt;h2&gt;
  
  
  This is where skills are useful
&lt;/h2&gt;

&lt;p&gt;Most teams do not need an agent that merely knows a gateway exists.&lt;/p&gt;

&lt;p&gt;They need an agent that knows how to migrate safely:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;inspect the codebase first&lt;/li&gt;
&lt;li&gt;identify provider-specific assumptions&lt;/li&gt;
&lt;li&gt;make the smallest useful change&lt;/li&gt;
&lt;li&gt;avoid leaking secrets&lt;/li&gt;
&lt;li&gt;preserve existing behavior&lt;/li&gt;
&lt;li&gt;verify the path after the edit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the difference between a tool and a workflow.&lt;/p&gt;

&lt;p&gt;The tool is the gateway.&lt;/p&gt;

&lt;p&gt;The workflow is how you introduce it without making the codebase harder to reason about.&lt;/p&gt;

&lt;p&gt;Source workflow:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://terminalskills.io/use-cases/route-ai-model-requests-through-routerbase" rel="noopener noreferrer"&gt;https://terminalskills.io/use-cases/route-ai-model-requests-through-routerbase&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Related skill:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://terminalskills.io/skills/routerbase-gateway" rel="noopener noreferrer"&gt;https://terminalskills.io/skills/routerbase-gateway&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The short version:&lt;/p&gt;

&lt;p&gt;If your AI app is starting to juggle providers, models, fallbacks, and media endpoints, do not scatter that logic through the product.&lt;/p&gt;

&lt;p&gt;Put it behind a gateway.&lt;/p&gt;

&lt;p&gt;Then teach the agent the migration workflow.&lt;/p&gt;

</description>
      <category>architecture</category>
    </item>
    <item>
      <title>Your AI Coding Agent Does Not Need a Refactor Prompt. It Needs an Architecture Workflow.</title>
      <dc:creator>Alex Shev</dc:creator>
      <pubDate>Sat, 11 Jul 2026 17:30:59 +0000</pubDate>
      <link>https://dev.to/alexshev/your-ai-coding-agent-does-not-need-a-refactor-prompt-it-needs-an-architecture-workflow-oof</link>
      <guid>https://dev.to/alexshev/your-ai-coding-agent-does-not-need-a-refactor-prompt-it-needs-an-architecture-workflow-oof</guid>
      <description>&lt;p&gt;Most AI refactoring advice starts in the wrong place.&lt;/p&gt;

&lt;p&gt;It assumes the hard part is telling the model what to change.&lt;/p&gt;

&lt;p&gt;So the prompt gets longer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Act as a senior architect.
Review this codebase.
Find refactoring opportunities.
Improve maintainability.
Make it more testable.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That sounds reasonable.&lt;/p&gt;

&lt;p&gt;But in a real repo, that prompt is too vague to be useful.&lt;/p&gt;

&lt;p&gt;The hard part is not asking for better architecture.&lt;/p&gt;

&lt;p&gt;The hard part is finding the parts of the codebase where architecture is actually hurting the work.&lt;/p&gt;

&lt;p&gt;Not every ugly file needs a refactor.&lt;br&gt;
Not every repeated function needs extraction.&lt;br&gt;
Not every small module is a good module.&lt;br&gt;
Not every "clean" interface hides useful complexity.&lt;/p&gt;

&lt;p&gt;Sometimes the code that looks messy is doing the real work.&lt;br&gt;
Sometimes the code that looks clean is only clean because the complexity was pushed into every caller.&lt;/p&gt;

&lt;p&gt;That is the part an AI coding agent needs help with.&lt;/p&gt;

&lt;p&gt;It needs an architecture workflow.&lt;/p&gt;


&lt;h2&gt;
  
  
  The problem with generic refactoring agents
&lt;/h2&gt;

&lt;p&gt;When I let an agent inspect a codebase with only a broad refactor instruction, it tends to do one of three things.&lt;/p&gt;

&lt;p&gt;First, it finds obvious style issues.&lt;/p&gt;

&lt;p&gt;Naming.&lt;br&gt;
Duplication.&lt;br&gt;
Large files.&lt;br&gt;
Missing comments.&lt;br&gt;
Inconsistent patterns.&lt;/p&gt;

&lt;p&gt;Those can matter, but they are rarely the architectural bottleneck.&lt;/p&gt;

&lt;p&gt;Second, it proposes interface extraction too early.&lt;/p&gt;

&lt;p&gt;The agent sees coupling, so it creates a service.&lt;br&gt;
It sees repeated logic, so it creates a helper.&lt;br&gt;
It sees conditionals, so it creates strategies.&lt;/p&gt;

&lt;p&gt;The code looks more "designed" afterward, but the system may become harder to understand because the same concept is now split across more files.&lt;/p&gt;

&lt;p&gt;Third, it treats testability as an extraction problem.&lt;/p&gt;

&lt;p&gt;If something is hard to test, the agent may pull small pure functions out of the flow until the tests become easy.&lt;/p&gt;

&lt;p&gt;That can make unit tests pleasant while hiding the real bugs in orchestration, boundaries, state, and integration behavior.&lt;/p&gt;

&lt;p&gt;The result is a codebase with more files, more seams, more mock points, and not necessarily better architecture.&lt;/p&gt;

&lt;p&gt;I do not want an agent to refactor like that.&lt;/p&gt;

&lt;p&gt;I want the agent to slow down and ask a better question:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Where did understanding this system become expensive?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Architectural friction is a better signal than file size
&lt;/h2&gt;

&lt;p&gt;A useful architecture pass should start by exploring the codebase the way a new senior engineer would.&lt;/p&gt;

&lt;p&gt;Not by counting lines.&lt;br&gt;
Not by ranking files by complexity score.&lt;br&gt;
Not by searching for "TODO".&lt;/p&gt;

&lt;p&gt;By following concepts.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Where does one business concept require bouncing through five shallow modules?&lt;/li&gt;
&lt;li&gt;Where is the public interface almost as complicated as the implementation?&lt;/li&gt;
&lt;li&gt;Where do callers need to know too much about internal sequencing?&lt;/li&gt;
&lt;li&gt;Where are tests mostly checking implementation details?&lt;/li&gt;
&lt;li&gt;Where do changes require touching several files that should probably move together?&lt;/li&gt;
&lt;li&gt;Where does the agent keep losing the thread while trying to understand one behavior?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last one is underrated.&lt;/p&gt;

&lt;p&gt;If an agent gets lost while navigating the repo, that is not only a model limitation.&lt;/p&gt;

&lt;p&gt;It may be an architecture signal.&lt;/p&gt;

&lt;p&gt;Humans feel this too. We just describe it differently:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Every change here takes longer than it should.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You have to know too much context before touching this module.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The tests pass, but I do not trust this area.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the layer worth investigating.&lt;/p&gt;




&lt;h2&gt;
  
  
  The deep module idea maps surprisingly well to agents
&lt;/h2&gt;

&lt;p&gt;John Ousterhout's deep module idea is still one of the best ways to think about this.&lt;/p&gt;

&lt;p&gt;A deep module has a small interface that hides meaningful complexity.&lt;/p&gt;

&lt;p&gt;That matters for humans because a good interface reduces the amount of system knowledge a developer needs to hold in their head.&lt;/p&gt;

&lt;p&gt;It matters for AI agents for the same reason.&lt;/p&gt;

&lt;p&gt;Agents are good at following local instructions.&lt;/p&gt;

&lt;p&gt;They are worse when every small change requires reconstructing a hidden social map of the repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;This helper is called here.
But only after this validation.
Unless this flag is set.
And this type is technically shared.
But this caller mutates it.
And the test mock does not match production behavior.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the implementation is scattered but the concept is unified, the agent has to infer the module boundary every time.&lt;/p&gt;

&lt;p&gt;That is waste.&lt;/p&gt;

&lt;p&gt;Good architecture gives both humans and agents a smaller surface to reason about.&lt;/p&gt;

&lt;p&gt;The goal is not fewer files.&lt;/p&gt;

&lt;p&gt;The goal is better boundaries.&lt;/p&gt;




&lt;h2&gt;
  
  
  A better workflow for agent-assisted architecture review
&lt;/h2&gt;

&lt;p&gt;The workflow I prefer has seven stages.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Explore before proposing
&lt;/h3&gt;

&lt;p&gt;The agent should walk the codebase and record friction.&lt;/p&gt;

&lt;p&gt;No refactor proposals yet.&lt;br&gt;
No new interfaces yet.&lt;br&gt;
No patches yet.&lt;/p&gt;

&lt;p&gt;Just exploration.&lt;/p&gt;

&lt;p&gt;The output should be a list of architectural friction points, not a list of code smells.&lt;/p&gt;

&lt;p&gt;For each candidate, I want:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the module or concept cluster involved&lt;/li&gt;
&lt;li&gt;why those files are coupled&lt;/li&gt;
&lt;li&gt;what state or behavior is spread across them&lt;/li&gt;
&lt;li&gt;what tests are hard to write or trust&lt;/li&gt;
&lt;li&gt;what kind of change becomes expensive there&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the step most refactor prompts skip.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Present candidates, not solutions
&lt;/h3&gt;

&lt;p&gt;The agent should show the candidates and ask which one to explore.&lt;/p&gt;

&lt;p&gt;That sounds small, but it prevents a common failure mode:&lt;/p&gt;

&lt;p&gt;The agent picks an area that looks bad but is not important.&lt;/p&gt;

&lt;p&gt;Architecture work should follow business and maintenance pressure.&lt;/p&gt;

&lt;p&gt;If an area is ugly but stable, it may not be the next refactor.&lt;/p&gt;

&lt;p&gt;If an area changes every week and every change creates review anxiety, that is a better target.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Frame the problem space
&lt;/h3&gt;

&lt;p&gt;Before designing anything, the agent should describe the constraints.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;This cluster handles customer eligibility.
It currently depends on plan state, billing status, account flags, and region rules.
The callers mostly need one decision: can this customer use this feature?
The current implementation exposes too many intermediate checks.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This framing is useful because it separates the problem from the proposed interface.&lt;/p&gt;

&lt;p&gt;The team can disagree with the framing before arguing about code.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Generate multiple interface designs
&lt;/h3&gt;

&lt;p&gt;One proposal is not enough.&lt;/p&gt;

&lt;p&gt;Architecture design benefits from contrast.&lt;/p&gt;

&lt;p&gt;I like asking separate agents, or separate passes, to design different interfaces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one minimal interface&lt;/li&gt;
&lt;li&gt;one flexible interface&lt;/li&gt;
&lt;li&gt;one optimized for the most common caller&lt;/li&gt;
&lt;li&gt;one ports-and-adapters version if external dependencies are involved&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The point is not to blindly choose the most elegant design.&lt;/p&gt;

&lt;p&gt;The point is to expose trade-offs.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Compare the designs in prose
&lt;/h3&gt;

&lt;p&gt;This is where the main agent should be opinionated.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Here are three options. Which do you prefer?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Option A is easiest to adopt but leaks dependency order.
Option B hides the right complexity but may be too abstract for current callers.
Option C is the strongest default because most callers only need one decision.
I would use C, with the error reporting shape from B.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the kind of help I actually want from an agent.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Turn the decision into an RFC
&lt;/h3&gt;

&lt;p&gt;Once the direction is chosen, do not jump straight to a giant PR.&lt;/p&gt;

&lt;p&gt;Create a refactor RFC issue.&lt;/p&gt;

&lt;p&gt;It should include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the current friction&lt;/li&gt;
&lt;li&gt;the chosen boundary&lt;/li&gt;
&lt;li&gt;the interface sketch&lt;/li&gt;
&lt;li&gt;migration plan&lt;/li&gt;
&lt;li&gt;test strategy&lt;/li&gt;
&lt;li&gt;risks&lt;/li&gt;
&lt;li&gt;what not to change yet&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This gives the team a reviewable architecture artifact before implementation begins.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Only then edit code
&lt;/h3&gt;

&lt;p&gt;The implementation should be the last step, not the first.&lt;/p&gt;

&lt;p&gt;If the agent starts by editing, it will often optimize the local patch instead of the architecture.&lt;/p&gt;

&lt;p&gt;The workflow has to force the design conversation first.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where Terminal Skills fits
&lt;/h2&gt;

&lt;p&gt;This is the kind of workflow that belongs in a skill, not in a one-off prompt.&lt;/p&gt;

&lt;p&gt;The Terminal Skills catalog has an &lt;code&gt;improve-codebase-architecture&lt;/code&gt; skill that packages this exact style of process:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://terminalskills.io/skills/improve-codebase-architecture" rel="noopener noreferrer"&gt;Improve Codebase Architecture on Terminal Skills&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is not a magic refactoring button.&lt;/p&gt;

&lt;p&gt;That is the point.&lt;/p&gt;

&lt;p&gt;It teaches the agent to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;explore the codebase organically&lt;/li&gt;
&lt;li&gt;treat navigation friction as a signal&lt;/li&gt;
&lt;li&gt;identify shallow modules and coupling clusters&lt;/li&gt;
&lt;li&gt;present candidates before proposing interfaces&lt;/li&gt;
&lt;li&gt;design multiple alternative boundaries&lt;/li&gt;
&lt;li&gt;compare trade-offs&lt;/li&gt;
&lt;li&gt;create a GitHub issue RFC instead of silently rewriting the system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Install command for Codex:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx terminal-skills &lt;span class="nb"&gt;install &lt;/span&gt;improve-codebase-architecture &lt;span class="nt"&gt;--agent&lt;/span&gt; codex
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Claude Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx terminal-skills &lt;span class="nb"&gt;install &lt;/span&gt;improve-codebase-architecture
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The native ad here is simple:&lt;/p&gt;

&lt;p&gt;If your agent keeps making refactors that look clean but do not make the codebase easier to change, do not give it a bigger prompt.&lt;/p&gt;

&lt;p&gt;Give it a repeatable architecture workflow.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this matters more now
&lt;/h2&gt;

&lt;p&gt;Agent skills are becoming a serious part of terminal-agent work.&lt;/p&gt;

&lt;p&gt;The ecosystem is moving in the same direction: reusable procedures are becoming a way to encode what to accomplish, when to apply it, and how to execute terminal tasks. The uncomfortable side is that skill retrieval, skill quality, and reusable automation can become fragile if the procedure is vague or unsafe.&lt;/p&gt;

&lt;p&gt;That matches what I see in practice.&lt;/p&gt;

&lt;p&gt;Skills are powerful when they are specific, procedural, and verifiable.&lt;/p&gt;

&lt;p&gt;They are weak when they are just long advice files.&lt;/p&gt;

&lt;p&gt;An architecture skill is a good test case because it cannot succeed by memorizing commands.&lt;/p&gt;

&lt;p&gt;It has to guide judgment.&lt;/p&gt;

&lt;p&gt;It has to slow the agent down.&lt;/p&gt;

&lt;p&gt;It has to preserve human decision points.&lt;/p&gt;

&lt;p&gt;It has to make the final artifact reviewable.&lt;/p&gt;

&lt;p&gt;That is what separates an agent workflow from an agent vibe.&lt;/p&gt;




&lt;h2&gt;
  
  
  My practical checklist
&lt;/h2&gt;

&lt;p&gt;If I were evaluating an architecture skill for a coding agent, I would ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does it force exploration before edits?&lt;/li&gt;
&lt;li&gt;Does it identify concept clusters, not just files?&lt;/li&gt;
&lt;li&gt;Does it distinguish coupling from duplication?&lt;/li&gt;
&lt;li&gt;Does it ask for human selection before deep design?&lt;/li&gt;
&lt;li&gt;Does it generate multiple interface options?&lt;/li&gt;
&lt;li&gt;Does it compare trade-offs in plain language?&lt;/li&gt;
&lt;li&gt;Does it produce an RFC before implementation?&lt;/li&gt;
&lt;li&gt;Does it define what should not be changed?&lt;/li&gt;
&lt;li&gt;Does it improve test boundaries instead of just adding mocks?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the answer is no, it is probably not an architecture workflow.&lt;/p&gt;

&lt;p&gt;It is just a refactor prompt wearing a better title.&lt;/p&gt;




&lt;h2&gt;
  
  
  The broader lesson
&lt;/h2&gt;

&lt;p&gt;AI agents are getting better at writing code.&lt;/p&gt;

&lt;p&gt;That makes architecture more important, not less.&lt;/p&gt;

&lt;p&gt;When the agent can produce a thousand-line refactor in minutes, the bottleneck shifts from typing to judgment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Was this the right boundary?
Did we hide the right complexity?
Did we make future changes easier?
Can the team review the decision?
Can the agent explain why it chose this shape?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those questions do not belong at the end of the PR.&lt;/p&gt;

&lt;p&gt;They belong in the workflow.&lt;/p&gt;

&lt;p&gt;That is why I think the next useful layer for AI coding agents is not more autonomous editing.&lt;/p&gt;

&lt;p&gt;It is better operating procedures.&lt;/p&gt;

&lt;p&gt;Skills are one way to package those procedures.&lt;/p&gt;

&lt;p&gt;And architecture review is one of the places where that packaging starts to matter.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: AI assistance was used to draft and edit this article.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>devtools</category>
      <category>refactoring</category>
    </item>
    <item>
      <title>The Local SEO Report Should Be an Agent Run, Not a Dashboard Screenshot</title>
      <dc:creator>Alex Shev</dc:creator>
      <pubDate>Fri, 03 Jul 2026 16:21:25 +0000</pubDate>
      <link>https://dev.to/alexshev/the-local-seo-report-should-be-an-agent-run-not-a-dashboard-screenshot-469i</link>
      <guid>https://dev.to/alexshev/the-local-seo-report-should-be-an-agent-run-not-a-dashboard-screenshot-469i</guid>
      <description>&lt;p&gt;Every local SEO agency has some version of the Monday reporting ritual.&lt;/p&gt;

&lt;p&gt;Someone opens a spreadsheet.&lt;/p&gt;

&lt;p&gt;Someone opens Google Business Profiles.&lt;/p&gt;

&lt;p&gt;Someone checks rankings for a few money keywords.&lt;/p&gt;

&lt;p&gt;Someone looks at reviews.&lt;/p&gt;

&lt;p&gt;Someone peeks at competitors.&lt;/p&gt;

&lt;p&gt;Then the team turns all of that into a client-friendly update that says what changed, what matters, and what needs approval.&lt;/p&gt;

&lt;p&gt;The work is valuable.&lt;/p&gt;

&lt;p&gt;The ritual is awful.&lt;/p&gt;

&lt;p&gt;It is repetitive, stateful, and full of tiny judgment calls:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;did the business drop out of the map pack?&lt;/li&gt;
&lt;li&gt;did a negative review arrive over the weekend?&lt;/li&gt;
&lt;li&gt;does the reply need owner approval?&lt;/li&gt;
&lt;li&gt;did a nearby competitor suddenly gain reviews?&lt;/li&gt;
&lt;li&gt;is this a real issue, or just noise?&lt;/li&gt;
&lt;li&gt;should the client act this week, or just keep watching?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is exactly the kind of workflow where I do not want an AI agent to "write an SEO report" from scratch.&lt;/p&gt;

&lt;p&gt;I want the agent to run the operating loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  The dashboard is not the workflow
&lt;/h2&gt;

&lt;p&gt;Dashboards are useful for humans.&lt;/p&gt;

&lt;p&gt;They are less useful as the primary interface for agents.&lt;/p&gt;

&lt;p&gt;A dashboard usually answers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What can I see if I click around?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An agent workflow needs a different interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What state exists?
What changed?
What should be checked next?
What requires approval?
What should never be done automatically?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That difference matters.&lt;/p&gt;

&lt;p&gt;Local SEO reporting is not just data extraction. It is a recurring workflow with memory:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;businesses already onboarded&lt;/li&gt;
&lt;li&gt;keywords already tracked&lt;/li&gt;
&lt;li&gt;ranking history over time&lt;/li&gt;
&lt;li&gt;reviews already answered or still pending&lt;/li&gt;
&lt;li&gt;competitors already on a watchlist&lt;/li&gt;
&lt;li&gt;locations that need neighborhood-specific checks&lt;/li&gt;
&lt;li&gt;client-specific rules around tone, compliance, and approval&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the agent only gets a screenshot or CSV export, it has to infer too much.&lt;/p&gt;

&lt;p&gt;If the agent gets a structured tool layer, it can operate much closer to the real job.&lt;/p&gt;

&lt;p&gt;That is why the SEOG skill on Terminal Skills is interesting to me.&lt;/p&gt;

&lt;p&gt;It turns local SEO monitoring into a terminal-native MCP workflow instead of another browser tab to babysit.&lt;/p&gt;

&lt;p&gt;Source skill: &lt;a href="https://terminalskills.io/skills/seog" rel="noopener noreferrer"&gt;SEOG on Terminal Skills&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Use case: &lt;a href="https://terminalskills.io/use-cases/automate-local-seo-agency-reporting" rel="noopener noreferrer"&gt;Automate Local SEO Monitoring for Client Businesses&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What the skill actually gives the agent
&lt;/h2&gt;

&lt;p&gt;The SEOG skill connects an AI coding agent to the SEOG MCP server.&lt;/p&gt;

&lt;p&gt;The platform is built around local businesses that live or die on Google Maps visibility: Google Business Profile data, map-pack rankings, reviews, and nearby competitors.&lt;/p&gt;

&lt;p&gt;The MCP server exposes those operations as tools.&lt;/p&gt;

&lt;p&gt;That is the important part.&lt;/p&gt;

&lt;p&gt;Instead of asking the agent to scrape pages or reason from a dashboard screenshot, the agent can call tools for the core entities in the workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;businesses&lt;/li&gt;
&lt;li&gt;keywords and rankings&lt;/li&gt;
&lt;li&gt;Google reviews&lt;/li&gt;
&lt;li&gt;competitors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The skill describes a streamable HTTP MCP endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add &lt;span class="nt"&gt;--transport&lt;/span&gt; http seog https://api.seog.ai/mcp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &amp;lt;your-seog-mcp-token&amp;gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, the agent can work through a structured local SEO loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;list_businesses
check_keyword
keyword_history
sync_reviews
list_reviews
draft_review_response
discover_competitors
snapshot_competitor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is a much better contract than:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Open my dashboard and tell me how things look.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The useful report is an impact queue
&lt;/h2&gt;

&lt;p&gt;A weak AI-generated SEO report sounds 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;Your local visibility is important. Reviews matter. Keep optimizing your profile.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Technically true.&lt;/p&gt;

&lt;p&gt;Completely useless.&lt;/p&gt;

&lt;p&gt;A useful local SEO report is closer to an impact queue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. You dropped from #2 to #5 for "emergency dentist near me" in Hyde Park.
2. Two new negative reviews need owner-approved replies.
3. A competitor within 1km added 43 reviews this month.
4. Your service page still does not match the GBP category you are trying to rank for.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the reporting shape agencies actually need.&lt;/p&gt;

&lt;p&gt;The agent should not just summarize.&lt;/p&gt;

&lt;p&gt;It should triage.&lt;/p&gt;

&lt;p&gt;The Terminal Skills use case frames this well: the agent checks rankings, syncs reviews, snapshots watched competitors, and writes a weekly digest with movement, unanswered negative reviews, drafted replies, and competitor alerts.&lt;/p&gt;

&lt;p&gt;The detail I like most is prioritization.&lt;/p&gt;

&lt;p&gt;A client dropping out of the 3-pack for a money keyword matters more than a 4-star review that has not been answered yet.&lt;/p&gt;

&lt;p&gt;That sounds obvious to an operator.&lt;/p&gt;

&lt;p&gt;It is not obvious to a generic writing model unless the workflow teaches it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Location context is not optional
&lt;/h2&gt;

&lt;p&gt;One trap in local SEO reporting is pretending that rankings are a single global number.&lt;/p&gt;

&lt;p&gt;They are not.&lt;/p&gt;

&lt;p&gt;For local businesses, the search location changes the answer.&lt;/p&gt;

&lt;p&gt;Checking from the agency office is often the wrong measurement.&lt;/p&gt;

&lt;p&gt;A coffee shop, dentist, med spa, or plumber may care about one neighborhood more than another. The useful question is not only:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Where do we rank?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Where do we rank from the places customers actually search?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is why I like seeing &lt;code&gt;locationLabel&lt;/code&gt; and coordinates as part of the keyword tracking flow.&lt;/p&gt;

&lt;p&gt;The agent can track a keyword from "Hyde Park" and "South Congress" instead of flattening the whole city into one report.&lt;/p&gt;

&lt;p&gt;That makes the weekly digest more honest.&lt;/p&gt;

&lt;p&gt;It also changes the recommendations.&lt;/p&gt;

&lt;p&gt;A business might be fine near its physical address but weak in the service area it wants to expand into. That is a different action item than "rankings are down."&lt;/p&gt;

&lt;h2&gt;
  
  
  Review replies should be draft-first
&lt;/h2&gt;

&lt;p&gt;This is the line I would not cross with automation:&lt;/p&gt;

&lt;p&gt;An agent can draft review replies.&lt;/p&gt;

&lt;p&gt;It should not silently publish them.&lt;/p&gt;

&lt;p&gt;The SEOG skill makes that boundary explicit: &lt;code&gt;draft_review_response&lt;/code&gt; saves a draft, but the owner approves in-app.&lt;/p&gt;

&lt;p&gt;That is the right design.&lt;/p&gt;

&lt;p&gt;Review replies are public. They touch customer trust. In medical, legal, home services, and other sensitive categories, a careless reply can create real problems.&lt;/p&gt;

&lt;p&gt;For regulated businesses, even a friendly response can go wrong if it confirms that someone was a customer or patient.&lt;/p&gt;

&lt;p&gt;So the automation boundary should look 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;Agent:
- finds reviews that need attention
- groups negative or risky reviews first
- drafts safe replies
- explains why each reply needs review

Human:
- approves
- edits
- publishes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is not a limitation.&lt;/p&gt;

&lt;p&gt;That is the workflow becoming safer.&lt;/p&gt;

&lt;p&gt;Good agent systems are not the ones that automate every click.&lt;/p&gt;

&lt;p&gt;They are the ones that know which clicks require approval.&lt;/p&gt;

&lt;h2&gt;
  
  
  Competitor monitoring is where the report gets interesting
&lt;/h2&gt;

&lt;p&gt;Most agencies already track their own client.&lt;/p&gt;

&lt;p&gt;The better reports also watch the local battlefield.&lt;/p&gt;

&lt;p&gt;If a nearby competitor suddenly gains review velocity, changes categories, adds services, or starts outranking the client for a money keyword, the client should hear about it before they notice it themselves.&lt;/p&gt;

&lt;p&gt;The SEOG workflow includes competitor discovery and snapshots:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;discover_competitors
add_competitor
set_competitor_watchlist
snapshot_competitor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That gives the agent a useful job:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Do not tell me everything.
Tell me what changed around this business.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the difference between reporting and monitoring.&lt;/p&gt;

&lt;p&gt;Reporting describes what happened.&lt;/p&gt;

&lt;p&gt;Monitoring notices what is starting to happen.&lt;/p&gt;

&lt;p&gt;For local SEO, that can be the difference between:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Your rankings dropped last month.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The competitor two blocks away is about to pass your review count. Start a compliant review request push now.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second one is much more valuable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The agent still needs guardrails
&lt;/h2&gt;

&lt;p&gt;This kind of workflow is also a good reminder that MCP tools are not enough by themselves.&lt;/p&gt;

&lt;p&gt;The skill has to teach operational boundaries.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;deleting a business is irreversible and should require confirmation&lt;/li&gt;
&lt;li&gt;live rank checks consume quota and should not run in tight loops&lt;/li&gt;
&lt;li&gt;review replies are drafts, not published responses&lt;/li&gt;
&lt;li&gt;API tokens are credentials and should never be logged or committed&lt;/li&gt;
&lt;li&gt;a 401 probably means the token was revoked and needs reissue&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those details are not decoration.&lt;/p&gt;

&lt;p&gt;They are the difference between a useful agent and a risky one.&lt;/p&gt;

&lt;p&gt;A generic model can understand "local SEO reporting."&lt;/p&gt;

&lt;p&gt;A skill can tell it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Do not delete this portfolio by accident.
Do not burn quota in a loop.
Do not claim a review reply was published.
Do not leak the token.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is exactly why I keep coming back to skills as the right abstraction for agent work.&lt;/p&gt;

&lt;p&gt;Prompts describe intent.&lt;/p&gt;

&lt;p&gt;Skills describe operating procedure.&lt;/p&gt;

&lt;h2&gt;
  
  
  A weekly agency run should look boring
&lt;/h2&gt;

&lt;p&gt;The best version of this workflow is not flashy.&lt;/p&gt;

&lt;p&gt;It is a scheduled run.&lt;/p&gt;

&lt;p&gt;Every Monday morning:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;For each client:
1. sync the business state
2. check active keywords by tracked location
3. compare rank movement against the last 7 days
4. sync reviews
5. draft replies for negative or unanswered reviews
6. snapshot watchlisted competitors
7. produce an impact-ranked digest
8. stop before anything public is published
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is boring in the best way.&lt;/p&gt;

&lt;p&gt;It gives the agency leverage without turning the account into an autopilot risk.&lt;/p&gt;

&lt;p&gt;The human still owns strategy, client communication, and approvals.&lt;/p&gt;

&lt;p&gt;The agent owns the repetitive monitoring loop.&lt;/p&gt;

&lt;p&gt;That is the split I trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bigger lesson
&lt;/h2&gt;

&lt;p&gt;I do not think the future of local SEO work is "AI writes reports."&lt;/p&gt;

&lt;p&gt;That is too shallow.&lt;/p&gt;

&lt;p&gt;The more useful shift is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI agents run recurring evidence-gathering workflows,
then hand humans a prioritized approval queue.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a local SEO agency, that queue might be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;rankings that moved&lt;/li&gt;
&lt;li&gt;reviews that need attention&lt;/li&gt;
&lt;li&gt;competitors that changed&lt;/li&gt;
&lt;li&gt;pages that need technical cleanup&lt;/li&gt;
&lt;li&gt;schema gaps&lt;/li&gt;
&lt;li&gt;business facts that no longer match across the web&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The report becomes a byproduct of the operating loop.&lt;/p&gt;

&lt;p&gt;That is the part worth building.&lt;/p&gt;

&lt;p&gt;If an agent can run the same checks every week, preserve state, respect approval boundaries, and explain what changed, it is no longer just generating content.&lt;/p&gt;

&lt;p&gt;It is doing operational work.&lt;/p&gt;

&lt;p&gt;And that is where agent skills start to feel less like prompt engineering and more like actual software.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>automation</category>
      <category>devtools</category>
      <category>seo</category>
    </item>
    <item>
      <title>The Blender Skill That Makes AI Agents Prove the Render Exists</title>
      <dc:creator>Alex Shev</dc:creator>
      <pubDate>Tue, 30 Jun 2026 21:36:15 +0000</pubDate>
      <link>https://dev.to/alexshev/the-blender-skill-that-makes-ai-agents-prove-the-render-exists-2e7o</link>
      <guid>https://dev.to/alexshev/the-blender-skill-that-makes-ai-agents-prove-the-render-exists-2e7o</guid>
      <description>&lt;p&gt;Most AI + Blender demos stop one step too early.&lt;/p&gt;

&lt;p&gt;The agent writes a script.&lt;/p&gt;

&lt;p&gt;The script looks plausible.&lt;/p&gt;

&lt;p&gt;The explanation sounds confident.&lt;/p&gt;

&lt;p&gt;But the real question is much simpler:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Did Blender actually render the thing?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is the line between a demo and a workflow.&lt;/p&gt;

&lt;p&gt;If an AI agent is helping with 3D production, the output cannot just be a paragraph of advice or a Python snippet that might work. At some point, the agent has to cross into the production layer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;configure the render engine&lt;/li&gt;
&lt;li&gt;set resolution and file format&lt;/li&gt;
&lt;li&gt;create or aim the camera&lt;/li&gt;
&lt;li&gt;set up lights&lt;/li&gt;
&lt;li&gt;apply materials&lt;/li&gt;
&lt;li&gt;render a frame or sequence&lt;/li&gt;
&lt;li&gt;verify that the output file exists&lt;/li&gt;
&lt;li&gt;return something the human can inspect&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is why I like the idea behind the &lt;code&gt;blender-render-automation&lt;/code&gt; skill on Terminal Skills.&lt;/p&gt;

&lt;p&gt;It is not trying to make Blender “magic.”&lt;/p&gt;

&lt;p&gt;It is trying to make Blender boring enough for an agent to operate.&lt;/p&gt;

&lt;p&gt;And boring is where real automation starts.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with AI-generated Blender scripts
&lt;/h2&gt;

&lt;p&gt;Blender has a powerful Python API.&lt;/p&gt;

&lt;p&gt;That makes it tempting to treat Blender automation as a code-generation problem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ask the agent for a bpy script.
Paste it into Blender.
Hope it works.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sometimes it does.&lt;/p&gt;

&lt;p&gt;Sometimes the script uses the wrong render engine name.&lt;/p&gt;

&lt;p&gt;Sometimes the camera points nowhere useful.&lt;/p&gt;

&lt;p&gt;Sometimes the material code assumes a node that is not there.&lt;/p&gt;

&lt;p&gt;Sometimes the render settings are incomplete.&lt;/p&gt;

&lt;p&gt;Sometimes the agent says “done” even though no image was written to disk.&lt;/p&gt;

&lt;p&gt;The annoying part is that these failures are not always dramatic. They are small production misses. The script almost works. The scene almost renders. The output almost matches what you asked for.&lt;/p&gt;

&lt;p&gt;But “almost” is expensive in 3D work.&lt;/p&gt;

&lt;p&gt;If you are creating product shots, thumbnails, animation previews, turntables, or review renders, the workflow needs a stronger contract than:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Here is some code you can try.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It needs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Here is the render output. Here is the path. Here is what was configured. Here is what still needs review.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A render skill is a definition of done
&lt;/h2&gt;

&lt;p&gt;The useful thing about a Blender render skill is not only that it knows &lt;code&gt;bpy&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The useful thing is that it teaches the agent what “done” means.&lt;/p&gt;

&lt;p&gt;For a render workflow, “done” should not mean:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the agent wrote a plausible answer&lt;/li&gt;
&lt;li&gt;the agent described Cycles vs EEVEE&lt;/li&gt;
&lt;li&gt;the agent generated a script and stopped&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It should mean:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Blender was run headlessly or through a known script path&lt;/li&gt;
&lt;li&gt;the render engine was explicitly configured&lt;/li&gt;
&lt;li&gt;output resolution and format were set&lt;/li&gt;
&lt;li&gt;cameras and lights were created or selected&lt;/li&gt;
&lt;li&gt;materials were applied with clear names&lt;/li&gt;
&lt;li&gt;a still frame or animation sequence was rendered&lt;/li&gt;
&lt;li&gt;the expected file appeared at the expected path&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is a much better interface for AI agents.&lt;/p&gt;

&lt;p&gt;It turns the task from “make a nice Blender thing” into a workflow with observable artifacts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why headless Blender matters
&lt;/h2&gt;

&lt;p&gt;Blender is a visual tool, but it can also run from the command line.&lt;/p&gt;

&lt;p&gt;That changes what an agent can do.&lt;/p&gt;

&lt;p&gt;Instead of manually clicking through the UI, the agent can operate through a repeatable loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;blender scene.blend &lt;span class="nt"&gt;--background&lt;/span&gt; &lt;span class="nt"&gt;--render-output&lt;/span&gt; /tmp/frame_ &lt;span class="nt"&gt;--render-frame&lt;/span&gt; 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;blender scene.blend &lt;span class="nt"&gt;--background&lt;/span&gt; &lt;span class="nt"&gt;--frame-start&lt;/span&gt; 1 &lt;span class="nt"&gt;--frame-end&lt;/span&gt; 100 &lt;span class="nt"&gt;--render-anim&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That loop is important because agents are much better when they can run something, inspect the result, and continue.&lt;/p&gt;

&lt;p&gt;A GUI-only workflow often leaves the agent guessing.&lt;/p&gt;

&lt;p&gt;A terminal workflow gives it evidence.&lt;/p&gt;

&lt;p&gt;The agent can check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;did the command exit successfully?&lt;/li&gt;
&lt;li&gt;did the PNG sequence appear?&lt;/li&gt;
&lt;li&gt;did the MP4 get created?&lt;/li&gt;
&lt;li&gt;did the output directory contain the expected frames?&lt;/li&gt;
&lt;li&gt;did the render crash halfway through?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those checks are not glamorous.&lt;/p&gt;

&lt;p&gt;They are exactly what make automation useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cycles, EEVEE, and choosing the right failure mode
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;blender-render-automation&lt;/code&gt; skill also points at an important production distinction: not every render needs the same engine.&lt;/p&gt;

&lt;p&gt;Cycles is physically accurate and better for final quality.&lt;/p&gt;

&lt;p&gt;EEVEE is fast and better for previews.&lt;/p&gt;

&lt;p&gt;That sounds obvious, but it matters for agents.&lt;/p&gt;

&lt;p&gt;If an agent always chooses the slowest path, it wastes time.&lt;/p&gt;

&lt;p&gt;If it always chooses the fastest path, it may return a preview that is not good enough for review.&lt;/p&gt;

&lt;p&gt;A good render workflow should make that choice explicit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use EEVEE for fast preview and layout checks&lt;/li&gt;
&lt;li&gt;use Cycles for final stills or higher-quality review frames&lt;/li&gt;
&lt;li&gt;enable denoising when samples are low&lt;/li&gt;
&lt;li&gt;use GPU rendering when the environment supports it&lt;/li&gt;
&lt;li&gt;avoid pretending a preview render is a final render&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That kind of operational judgment is exactly what belongs in a skill.&lt;/p&gt;

&lt;p&gt;The model can still reason about the task.&lt;/p&gt;

&lt;p&gt;But the workflow gives it defaults that are safer than fresh improvisation every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cameras and lights are not decoration
&lt;/h2&gt;

&lt;p&gt;A lot of failed AI-Blender attempts are not really modeling failures.&lt;/p&gt;

&lt;p&gt;They are camera and lighting failures.&lt;/p&gt;

&lt;p&gt;The object exists.&lt;/p&gt;

&lt;p&gt;The scene exists.&lt;/p&gt;

&lt;p&gt;But the camera misses the subject, the focal length is wrong, the light is too weak, or the result is technically rendered but useless.&lt;/p&gt;

&lt;p&gt;A render automation skill can push the agent to treat cameras and lights as part of the deliverable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create a camera at a known location&lt;/li&gt;
&lt;li&gt;aim it at the subject&lt;/li&gt;
&lt;li&gt;use a reasonable focal length&lt;/li&gt;
&lt;li&gt;add area lights or environment lighting&lt;/li&gt;
&lt;li&gt;name cameras clearly&lt;/li&gt;
&lt;li&gt;batch render multiple camera views when needed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is especially useful for product work.&lt;/p&gt;

&lt;p&gt;One render is rarely enough.&lt;/p&gt;

&lt;p&gt;A human reviewer may need a hero angle, front view, side view, top view, and a transparent-background version.&lt;/p&gt;

&lt;p&gt;That should not require five separate improvisations.&lt;/p&gt;

&lt;p&gt;It should be a repeatable operation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Render animations as image sequences first
&lt;/h2&gt;

&lt;p&gt;One of the best small rules in render automation is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Render animations as image sequences before assembling video.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That sounds like old-school pipeline advice because it is.&lt;/p&gt;

&lt;p&gt;It is also exactly the kind of rule AI agents need.&lt;/p&gt;

&lt;p&gt;If a direct video render fails at frame 87, you may lose the whole output or have a painful recovery path.&lt;/p&gt;

&lt;p&gt;If an image sequence fails at frame 87, frames 1-86 still exist.&lt;/p&gt;

&lt;p&gt;The agent can inspect what completed, rerun the missing range, and then assemble the sequence with FFmpeg.&lt;/p&gt;

&lt;p&gt;That is a production workflow.&lt;/p&gt;

&lt;p&gt;It is not just a Blender trick.&lt;/p&gt;

&lt;p&gt;It is a reliability pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Prefer recoverable intermediate artifacts over one fragile final artifact.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That pattern applies far beyond Blender.&lt;/p&gt;

&lt;p&gt;But Blender makes it very visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Materials need conventions, not vibes
&lt;/h2&gt;

&lt;p&gt;When a human says “make it premium,” an agent can generate endless material ideas.&lt;/p&gt;

&lt;p&gt;That is not always helpful.&lt;/p&gt;

&lt;p&gt;Production scenes need conventions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;named materials&lt;/li&gt;
&lt;li&gt;predictable PBR settings&lt;/li&gt;
&lt;li&gt;sane roughness and metallic values&lt;/li&gt;
&lt;li&gt;glass separated from plastic and metal&lt;/li&gt;
&lt;li&gt;transparent-background settings when needed&lt;/li&gt;
&lt;li&gt;output formats chosen for the downstream use case&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A render skill does not remove taste from the process.&lt;/p&gt;

&lt;p&gt;It keeps the mechanical layer consistent so the human can spend attention on the creative layer.&lt;/p&gt;

&lt;p&gt;That is the right division of labor.&lt;/p&gt;

&lt;p&gt;The agent handles setup, naming, rendering, and verification.&lt;/p&gt;

&lt;p&gt;The human judges whether the result is good.&lt;/p&gt;

&lt;h2&gt;
  
  
  The real product is the workflow boundary
&lt;/h2&gt;

&lt;p&gt;When people talk about AI agents and creative tools, the conversation often jumps to autonomy.&lt;/p&gt;

&lt;p&gt;Can the agent make a complete scene by itself?&lt;/p&gt;

&lt;p&gt;Can it replace a 3D artist?&lt;/p&gt;

&lt;p&gt;Can it generate a finished animation from one sentence?&lt;/p&gt;

&lt;p&gt;I think that is the wrong starting point.&lt;/p&gt;

&lt;p&gt;The more useful question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can the agent own a narrow, repeatable production step?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For Blender rendering, that step might be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;set up a studio render scene&lt;/li&gt;
&lt;li&gt;render a transparent PNG&lt;/li&gt;
&lt;li&gt;create a 36-frame turntable&lt;/li&gt;
&lt;li&gt;generate a contact sheet from multiple cameras&lt;/li&gt;
&lt;li&gt;render an animation sequence&lt;/li&gt;
&lt;li&gt;produce preview and final variants&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is a realistic agent workflow.&lt;/p&gt;

&lt;p&gt;It does not need to replace the artist.&lt;/p&gt;

&lt;p&gt;It needs to remove the repetitive setup work around the artist.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters for agent skills
&lt;/h2&gt;

&lt;p&gt;The bigger lesson is not only about Blender.&lt;/p&gt;

&lt;p&gt;It is about how we package work for AI agents.&lt;/p&gt;

&lt;p&gt;A model can know a lot and still fail at the last mile.&lt;/p&gt;

&lt;p&gt;Skills help close that gap by giving the agent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a trigger for when the workflow applies&lt;/li&gt;
&lt;li&gt;operational steps&lt;/li&gt;
&lt;li&gt;command patterns&lt;/li&gt;
&lt;li&gt;quality checks&lt;/li&gt;
&lt;li&gt;failure modes&lt;/li&gt;
&lt;li&gt;a definition of done&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is why I keep coming back to Terminal Skills as a useful layer.&lt;/p&gt;

&lt;p&gt;It treats skills less like prompt decorations and more like small workflow contracts.&lt;/p&gt;

&lt;p&gt;For Blender, that contract is easy to understand:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do not just describe the render. Produce it, verify it, and tell me where it is.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is the part agents need.&lt;/p&gt;

&lt;p&gt;Not more confidence.&lt;/p&gt;

&lt;p&gt;More proof.&lt;/p&gt;




&lt;p&gt;The skill I am talking about is &lt;code&gt;blender-render-automation&lt;/code&gt; on Terminal Skills:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://terminalskills.io/skills/blender-render-automation" rel="noopener noreferrer"&gt;https://terminalskills.io/skills/blender-render-automation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are experimenting with AI agents and Blender, I would start with one narrow workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Create a clean product scene, render one preview, verify the image exists, and return the output path.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is not flashy.&lt;/p&gt;

&lt;p&gt;But it is the right kind of boring.&lt;/p&gt;

&lt;p&gt;And once that works, you can build a real pipeline on top of it.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devtools</category>
      <category>blender</category>
      <category>automation</category>
    </item>
    <item>
      <title>ComfyUI Is Becoming the Workflow Layer for AI Image Agents</title>
      <dc:creator>Alex Shev</dc:creator>
      <pubDate>Sat, 27 Jun 2026 17:46:10 +0000</pubDate>
      <link>https://dev.to/alexshev/comfyui-is-becoming-the-workflow-layer-for-ai-image-agents-8jo</link>
      <guid>https://dev.to/alexshev/comfyui-is-becoming-the-workflow-layer-for-ai-image-agents-8jo</guid>
      <description>&lt;p&gt;Most image generation tutorials still treat ComfyUI like a visual playground.&lt;/p&gt;

&lt;p&gt;Open the UI.&lt;br&gt;
Drag a few nodes together.&lt;br&gt;
Load a checkpoint.&lt;br&gt;
Generate an image.&lt;/p&gt;

&lt;p&gt;That is useful, but it undersells why ComfyUI keeps mattering.&lt;/p&gt;

&lt;p&gt;The more interesting shift is this:&lt;/p&gt;

&lt;p&gt;ComfyUI is not just a UI for image generation anymore. It is becoming a workflow layer.&lt;/p&gt;

&lt;p&gt;That matters a lot for AI agents.&lt;/p&gt;

&lt;p&gt;An agent does not only need to write a prompt. It needs to run a repeatable process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;choose the right model&lt;/li&gt;
&lt;li&gt;place files in the right folders&lt;/li&gt;
&lt;li&gt;load the workflow&lt;/li&gt;
&lt;li&gt;queue the job&lt;/li&gt;
&lt;li&gt;wait for completion&lt;/li&gt;
&lt;li&gt;retrieve the output&lt;/li&gt;
&lt;li&gt;verify that the output exists&lt;/li&gt;
&lt;li&gt;adapt the graph for the next run&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A plain prompt does not give you that.&lt;/p&gt;

&lt;p&gt;A graph does.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why the graph matters
&lt;/h2&gt;

&lt;p&gt;The big advantage of ComfyUI is that the workflow is explicit.&lt;/p&gt;

&lt;p&gt;Instead of hiding the image pipeline behind one text box, ComfyUI exposes the steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;checkpoint loading&lt;/li&gt;
&lt;li&gt;prompt encoding&lt;/li&gt;
&lt;li&gt;latent image creation&lt;/li&gt;
&lt;li&gt;sampling&lt;/li&gt;
&lt;li&gt;VAE decoding&lt;/li&gt;
&lt;li&gt;image saving&lt;/li&gt;
&lt;li&gt;ControlNet inputs&lt;/li&gt;
&lt;li&gt;LoRA loading&lt;/li&gt;
&lt;li&gt;upscaling&lt;/li&gt;
&lt;li&gt;custom nodes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That can look intimidating at first, but it is exactly what makes ComfyUI useful for serious automation.&lt;/p&gt;

&lt;p&gt;If an image workflow is just a prompt, an agent has to guess what happened.&lt;/p&gt;

&lt;p&gt;If an image workflow is a graph, an agent can inspect the moving parts.&lt;/p&gt;

&lt;p&gt;It can reason about the graph. It can reuse it. It can change one piece without rewriting the whole pipeline.&lt;/p&gt;

&lt;p&gt;That is the difference between "generate something like this" and "run this visual production workflow again with different inputs."&lt;/p&gt;
&lt;h2&gt;
  
  
  Agents need workflows, not vibes
&lt;/h2&gt;

&lt;p&gt;For casual generation, a prompt box is fine.&lt;/p&gt;

&lt;p&gt;For production work, the weak point is rarely the first image.&lt;/p&gt;

&lt;p&gt;The weak point is consistency.&lt;/p&gt;

&lt;p&gt;Can you run the same style again?&lt;br&gt;
Can you swap the input image?&lt;br&gt;
Can you keep the ControlNet guide but change the subject?&lt;br&gt;
Can you send the result into an upscale pass?&lt;br&gt;
Can you use the same workflow from a script instead of clicking through the UI?&lt;/p&gt;

&lt;p&gt;That is where ComfyUI starts to feel less like an art tool and more like infrastructure.&lt;/p&gt;

&lt;p&gt;The workflow JSON becomes the contract.&lt;/p&gt;

&lt;p&gt;The agent does not need to remember every step from scratch. It can submit the workflow, poll for the result, download the output, then report what happened.&lt;/p&gt;
&lt;h2&gt;
  
  
  The API is the underrated part
&lt;/h2&gt;

&lt;p&gt;The visual graph is what people notice first.&lt;/p&gt;

&lt;p&gt;The API is what makes it automation-friendly.&lt;/p&gt;

&lt;p&gt;A normal agent path looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start ComfyUI locally or on a GPU box.&lt;/li&gt;
&lt;li&gt;Load or generate a workflow JSON.&lt;/li&gt;
&lt;li&gt;Submit that workflow to the &lt;code&gt;/prompt&lt;/code&gt; endpoint.&lt;/li&gt;
&lt;li&gt;Poll &lt;code&gt;/history/{prompt_id}&lt;/code&gt; until the job completes.&lt;/li&gt;
&lt;li&gt;Fetch the generated image through &lt;code&gt;/view&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Save the output into a known folder.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That is a much better fit for agents than browser-only image generation.&lt;/p&gt;

&lt;p&gt;The agent can run the same workflow from code. It can log prompt IDs. It can keep output paths stable. It can fail cleanly when the server is down or a model file is missing.&lt;/p&gt;

&lt;p&gt;That is not glamorous, but it is what makes the workflow usable.&lt;/p&gt;
&lt;h2&gt;
  
  
  The setup details are the real trap
&lt;/h2&gt;

&lt;p&gt;The hard part is not only "how do I use ComfyUI?"&lt;/p&gt;

&lt;p&gt;The hard part is all the small operational details around it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;which Python version is expected&lt;/li&gt;
&lt;li&gt;which CUDA or ROCm path is being used&lt;/li&gt;
&lt;li&gt;where checkpoint files belong&lt;/li&gt;
&lt;li&gt;where LoRAs belong&lt;/li&gt;
&lt;li&gt;where ControlNet models belong&lt;/li&gt;
&lt;li&gt;how custom nodes are installed&lt;/li&gt;
&lt;li&gt;how to run ComfyUI in Docker with GPU access&lt;/li&gt;
&lt;li&gt;how to avoid losing outputs in random folders&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These details are boring, but agents break on boring details.&lt;/p&gt;

&lt;p&gt;That is why I like packaging this kind of workflow as a skill instead of leaving it as a loose note.&lt;/p&gt;

&lt;p&gt;For example, I keep a ComfyUI Terminal Skill here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://terminalskills.io/skills/comfyui" rel="noopener noreferrer"&gt;https://terminalskills.io/skills/comfyui&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The point is not "here is another page to read."&lt;/p&gt;

&lt;p&gt;The point is that an agent needs a repeatable operating path. The skill gives it the ComfyUI install shape, model folder conventions, API queue example, result polling, custom node setup, ControlNet pattern, and Docker deployment notes in one place.&lt;/p&gt;

&lt;p&gt;So when the task is "use ComfyUI for this workflow," the agent is not starting from search results. It has a known path through the tool.&lt;/p&gt;

&lt;p&gt;You can also install it directly for an agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx terminal-skills &lt;span class="nb"&gt;install &lt;/span&gt;comfyui &lt;span class="nt"&gt;--agent&lt;/span&gt; codex
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the useful version of documentation for agent work: not a brochure, not a generic tutorial, but a compact workflow the agent can act on.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical ComfyUI agent workflow
&lt;/h2&gt;

&lt;p&gt;If I were building an agent-controlled ComfyUI flow, I would keep it simple at first.&lt;/p&gt;

&lt;p&gt;Start with one known working workflow.&lt;/p&gt;

&lt;p&gt;Do not begin with ten custom node packs and a giant experimental graph.&lt;/p&gt;

&lt;p&gt;Use a small txt2img or img2img workflow and make the agent prove it can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;start or reach the ComfyUI server&lt;/li&gt;
&lt;li&gt;submit one workflow&lt;/li&gt;
&lt;li&gt;capture the prompt ID&lt;/li&gt;
&lt;li&gt;wait for completion&lt;/li&gt;
&lt;li&gt;download the generated file&lt;/li&gt;
&lt;li&gt;verify the file exists&lt;/li&gt;
&lt;li&gt;report the exact output path&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Only after that would I add more complexity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ControlNet&lt;/li&gt;
&lt;li&gt;LoRA variants&lt;/li&gt;
&lt;li&gt;upscale passes&lt;/li&gt;
&lt;li&gt;image prompt adapters&lt;/li&gt;
&lt;li&gt;animation nodes&lt;/li&gt;
&lt;li&gt;batch generation&lt;/li&gt;
&lt;li&gt;remote GPU deployment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first milestone is not a beautiful image.&lt;/p&gt;

&lt;p&gt;The first milestone is a reliable loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters for creative automation
&lt;/h2&gt;

&lt;p&gt;ComfyUI is one of the places where AI image work becomes more like software engineering.&lt;/p&gt;

&lt;p&gt;You do not just write a prompt.&lt;/p&gt;

&lt;p&gt;You build a pipeline.&lt;/p&gt;

&lt;p&gt;That pipeline can be versioned, reused, inspected, debugged, and called from code.&lt;/p&gt;

&lt;p&gt;For human artists, that gives more control.&lt;/p&gt;

&lt;p&gt;For AI agents, it gives something even more important: structure.&lt;/p&gt;

&lt;p&gt;Agents are much more useful when the workflow has shape.&lt;/p&gt;

&lt;p&gt;ComfyUI gives image generation that shape.&lt;/p&gt;

&lt;p&gt;And once the workflow is explicit, the agent can stop guessing and start operating.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devtools</category>
      <category>machinelearning</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Your Wix Site Is Not the Problem. The Migration Workflow Is.</title>
      <dc:creator>Alex Shev</dc:creator>
      <pubDate>Fri, 19 Jun 2026 02:32:16 +0000</pubDate>
      <link>https://dev.to/alexshev/your-wix-site-is-not-the-problem-the-migration-workflow-is-4b4c</link>
      <guid>https://dev.to/alexshev/your-wix-site-is-not-the-problem-the-migration-workflow-is-4b4c</guid>
      <description>&lt;p&gt;Wix is good at the thing it was built for.&lt;/p&gt;

&lt;p&gt;It lets someone get a website online without opening a repo, choosing a framework, setting up hosting, wiring a CMS, or learning deployment.&lt;/p&gt;

&lt;p&gt;That is useful.&lt;/p&gt;

&lt;p&gt;For a lot of businesses, a Wix site is not a mistake. It is the reason they had a website at all.&lt;/p&gt;

&lt;p&gt;The problem usually starts later.&lt;/p&gt;

&lt;p&gt;The site grows. The business changes. Marketing wants better landing pages. SEO becomes more serious. Someone wants custom checkout logic. Someone wants the blog to behave differently. Someone wants better performance. Someone wants a dashboard, a pricing page, a gated area, a headless CMS, or a proper deployment workflow.&lt;/p&gt;

&lt;p&gt;And suddenly the team says:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Can we move this Wix site to React?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That question sounds simple.&lt;/p&gt;

&lt;p&gt;It is not.&lt;/p&gt;

&lt;p&gt;There is no clean universal "export to Next.js" button for the real version of this job.&lt;/p&gt;

&lt;p&gt;You are not just moving pixels.&lt;/p&gt;

&lt;p&gt;You are moving a live website with content, layout decisions, SEO assumptions, forms, media, tracking, business logic, and usually a few messy surprises nobody documented.&lt;/p&gt;

&lt;p&gt;That is why Wix-to-React migration is a workflow problem, not a framework problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  The naive version of this task
&lt;/h2&gt;

&lt;p&gt;The naive version sounds 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;Take this Wix site and rebuild it in React.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An AI agent can try.&lt;/p&gt;

&lt;p&gt;It can open the page, inspect the layout, create a component, copy some text, approximate the styling, and produce something that looks close enough in a screenshot.&lt;/p&gt;

&lt;p&gt;That is fine for a demo.&lt;/p&gt;

&lt;p&gt;It is not enough for a migration.&lt;/p&gt;

&lt;p&gt;Because the first screenshot is not the website.&lt;/p&gt;

&lt;p&gt;The website is also:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;all the pages you forgot to mention&lt;/li&gt;
&lt;li&gt;mobile layouts&lt;/li&gt;
&lt;li&gt;navigation states&lt;/li&gt;
&lt;li&gt;images and files&lt;/li&gt;
&lt;li&gt;redirects&lt;/li&gt;
&lt;li&gt;metadata&lt;/li&gt;
&lt;li&gt;forms&lt;/li&gt;
&lt;li&gt;blog posts&lt;/li&gt;
&lt;li&gt;product pages&lt;/li&gt;
&lt;li&gt;CMS collections&lt;/li&gt;
&lt;li&gt;tracking scripts&lt;/li&gt;
&lt;li&gt;accessibility issues&lt;/li&gt;
&lt;li&gt;weird spacing that only exists on one page&lt;/li&gt;
&lt;li&gt;business content that is hidden behind menus&lt;/li&gt;
&lt;li&gt;SEO URLs that should not break&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you treat the job like a design clone, you miss the operational work.&lt;/p&gt;

&lt;p&gt;If you treat it like an operational migration, the task becomes much clearer.&lt;/p&gt;




&lt;h2&gt;
  
  
  The real question
&lt;/h2&gt;

&lt;p&gt;The real question is not:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Can React recreate this page?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course it can.&lt;/p&gt;

&lt;p&gt;The better question is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What exactly needs to survive the move?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That question changes the whole workflow.&lt;/p&gt;

&lt;p&gt;A brochure site with five static pages is one thing.&lt;/p&gt;

&lt;p&gt;A Wix site with blog content, member areas, forms, stores, bookings, and SEO history is another.&lt;/p&gt;

&lt;p&gt;For a small static site, you might rebuild everything in Next.js and move on.&lt;/p&gt;

&lt;p&gt;For a site using Wix CMS or Wix Stores, you have decisions to make:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;do you migrate the data out of Wix?&lt;/li&gt;
&lt;li&gt;do you keep Wix as a headless backend?&lt;/li&gt;
&lt;li&gt;do you recreate the CMS somewhere else?&lt;/li&gt;
&lt;li&gt;do you preserve the URL structure?&lt;/li&gt;
&lt;li&gt;do you rebuild forms manually?&lt;/li&gt;
&lt;li&gt;do you map products to a new ecommerce system?&lt;/li&gt;
&lt;li&gt;do you keep any Wix SDK integration?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are not code-generation questions.&lt;/p&gt;

&lt;p&gt;They are migration design questions.&lt;/p&gt;

&lt;p&gt;And if you skip them, the React app may look fine while the business workflow breaks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why agents need a skill for this
&lt;/h2&gt;

&lt;p&gt;AI agents are pretty good at writing React components.&lt;/p&gt;

&lt;p&gt;They are less reliable when the task is open-ended and the definition of "done" is fuzzy.&lt;/p&gt;

&lt;p&gt;That is exactly what a Wix migration is.&lt;/p&gt;

&lt;p&gt;Without a workflow, the agent might do the most obvious thing:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;open the homepage&lt;/li&gt;
&lt;li&gt;copy the visual layout&lt;/li&gt;
&lt;li&gt;create a few components&lt;/li&gt;
&lt;li&gt;call it a migration&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But a real migration needs a more boring sequence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;inventory -&amp;gt; classify -&amp;gt; extract -&amp;gt; rebuild -&amp;gt; migrate data -&amp;gt; verify -&amp;gt; report gaps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is not glamorous.&lt;/p&gt;

&lt;p&gt;It is also the difference between a useful migration and a pretty mockup.&lt;/p&gt;

&lt;p&gt;This is where Terminal Skills becomes relevant.&lt;/p&gt;

&lt;p&gt;Terminal Skills is a catalog of reusable skills for AI agents. The point is not to give the agent one magic command. The point is to give it a repeatable operating procedure.&lt;/p&gt;

&lt;p&gt;For this exact problem, the useful skill is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wix-to-react
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The skill page is here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://terminalskills.io/skills/wix-to-react
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part is the shape of the workflow.&lt;/p&gt;

&lt;p&gt;It tells the agent to treat a Wix-to-React conversion as a migration with inspection, decisions, preservation rules, and verification, not as a one-shot clone.&lt;/p&gt;




&lt;h2&gt;
  
  
  What a Wix-to-React workflow should do first
&lt;/h2&gt;

&lt;p&gt;The first step should not be code.&lt;/p&gt;

&lt;p&gt;The first step should be inventory.&lt;/p&gt;

&lt;p&gt;Before the agent builds anything, it should answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how many pages exist?&lt;/li&gt;
&lt;li&gt;which pages are public?&lt;/li&gt;
&lt;li&gt;which pages are hidden or linked only from menus?&lt;/li&gt;
&lt;li&gt;what content is static?&lt;/li&gt;
&lt;li&gt;what content comes from Wix CMS?&lt;/li&gt;
&lt;li&gt;are there blog posts?&lt;/li&gt;
&lt;li&gt;are there products?&lt;/li&gt;
&lt;li&gt;are there forms?&lt;/li&gt;
&lt;li&gt;are there bookings, events, or members-only areas?&lt;/li&gt;
&lt;li&gt;what scripts are installed?&lt;/li&gt;
&lt;li&gt;what URLs need to be preserved?&lt;/li&gt;
&lt;li&gt;what assets need to be downloaded?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not busywork.&lt;/p&gt;

&lt;p&gt;This prevents the classic migration failure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The homepage was rebuilt, but half the website disappeared.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The homepage is usually the easiest page.&lt;/p&gt;

&lt;p&gt;The risk is in the boring pages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;thank-you pages&lt;/li&gt;
&lt;li&gt;old campaign landing pages&lt;/li&gt;
&lt;li&gt;policy pages&lt;/li&gt;
&lt;li&gt;blog detail templates&lt;/li&gt;
&lt;li&gt;category pages&lt;/li&gt;
&lt;li&gt;product variants&lt;/li&gt;
&lt;li&gt;forms connected to business processes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If those pages are not inventoried, they are easy to lose.&lt;/p&gt;




&lt;h2&gt;
  
  
  The second step is classification
&lt;/h2&gt;

&lt;p&gt;Once you know what exists, you need to classify it.&lt;/p&gt;

&lt;p&gt;Not every part of a Wix site should be migrated the same way.&lt;/p&gt;

&lt;p&gt;I would separate it like this:&lt;/p&gt;

&lt;h3&gt;
  
  
  Static marketing pages
&lt;/h3&gt;

&lt;p&gt;These are usually safe to rebuild directly in React or Next.js.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;homepage&lt;/li&gt;
&lt;li&gt;about page&lt;/li&gt;
&lt;li&gt;service pages&lt;/li&gt;
&lt;li&gt;contact page&lt;/li&gt;
&lt;li&gt;pricing page&lt;/li&gt;
&lt;li&gt;landing pages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The agent can rebuild these as components, sections, layouts, and reusable content blocks.&lt;/p&gt;

&lt;h3&gt;
  
  
  CMS-driven content
&lt;/h3&gt;

&lt;p&gt;This needs a data decision.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;blog posts&lt;/li&gt;
&lt;li&gt;case studies&lt;/li&gt;
&lt;li&gt;team members&lt;/li&gt;
&lt;li&gt;locations&lt;/li&gt;
&lt;li&gt;service areas&lt;/li&gt;
&lt;li&gt;resource libraries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can migrate this to another CMS, keep it in files, move it into a database, or use Wix as a headless backend through the Wix SDK.&lt;/p&gt;

&lt;p&gt;But the decision needs to be explicit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Business logic
&lt;/h3&gt;

&lt;p&gt;This is where a screenshot clone fails badly.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;forms&lt;/li&gt;
&lt;li&gt;bookings&lt;/li&gt;
&lt;li&gt;ecommerce&lt;/li&gt;
&lt;li&gt;member areas&lt;/li&gt;
&lt;li&gt;gated downloads&lt;/li&gt;
&lt;li&gt;payment flows&lt;/li&gt;
&lt;li&gt;email automations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are not visual elements.&lt;/p&gt;

&lt;p&gt;They are workflows.&lt;/p&gt;

&lt;p&gt;If the old site uses Wix Forms or Wix Stores, the new React app needs a replacement plan.&lt;/p&gt;

&lt;h3&gt;
  
  
  SEO and analytics
&lt;/h3&gt;

&lt;p&gt;This is easy to forget because it does not show up in the page design.&lt;/p&gt;

&lt;p&gt;But it matters.&lt;/p&gt;

&lt;p&gt;The migration should preserve or map:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;page titles&lt;/li&gt;
&lt;li&gt;meta descriptions&lt;/li&gt;
&lt;li&gt;canonical URLs&lt;/li&gt;
&lt;li&gt;open graph images&lt;/li&gt;
&lt;li&gt;headings&lt;/li&gt;
&lt;li&gt;structured data&lt;/li&gt;
&lt;li&gt;redirects&lt;/li&gt;
&lt;li&gt;analytics events&lt;/li&gt;
&lt;li&gt;pixels&lt;/li&gt;
&lt;li&gt;conversion tracking&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a business already gets traffic from the Wix site, migration is not just a design task.&lt;/p&gt;

&lt;p&gt;It is a traffic-preservation task.&lt;/p&gt;




&lt;h2&gt;
  
  
  Rebuilding the UI is the easy part
&lt;/h2&gt;

&lt;p&gt;Once the inventory and classification are done, the React work becomes much easier.&lt;/p&gt;

&lt;p&gt;The agent can create:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a layout system&lt;/li&gt;
&lt;li&gt;shared header and footer&lt;/li&gt;
&lt;li&gt;reusable section components&lt;/li&gt;
&lt;li&gt;page templates&lt;/li&gt;
&lt;li&gt;image components&lt;/li&gt;
&lt;li&gt;content loaders&lt;/li&gt;
&lt;li&gt;route structure&lt;/li&gt;
&lt;li&gt;SEO metadata helpers&lt;/li&gt;
&lt;li&gt;form components&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where React and Next.js shine.&lt;/p&gt;

&lt;p&gt;Instead of editing every page manually inside a visual builder, you can create a system.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;components/
  Header.tsx
  Footer.tsx
  Hero.tsx
  ServiceGrid.tsx
  TestimonialSection.tsx
  ContactForm.tsx

app/
  page.tsx
  about/page.tsx
  services/[slug]/page.tsx
  blog/[slug]/page.tsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal is not to recreate Wix as code.&lt;/p&gt;

&lt;p&gt;The goal is to turn the site into a maintainable product.&lt;/p&gt;

&lt;p&gt;That means reusable components, clear content sources, predictable routes, and a deployment workflow the team can understand.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Wix SDK option
&lt;/h2&gt;

&lt;p&gt;There is one important nuance.&lt;/p&gt;

&lt;p&gt;Moving to React does not always mean abandoning Wix completely.&lt;/p&gt;

&lt;p&gt;For some teams, Wix still owns useful business data:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;products&lt;/li&gt;
&lt;li&gt;CMS collections&lt;/li&gt;
&lt;li&gt;bookings&lt;/li&gt;
&lt;li&gt;members&lt;/li&gt;
&lt;li&gt;blog content&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In that case, the migration may become:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;React/Next.js frontend + Wix as backend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is where &lt;code&gt;@wix/sdk&lt;/code&gt; can matter.&lt;/p&gt;

&lt;p&gt;Instead of ripping everything out immediately, the new app can use Wix data as a headless backend while the frontend becomes custom.&lt;/p&gt;

&lt;p&gt;That is not the right answer for every project.&lt;/p&gt;

&lt;p&gt;But it is a real migration option.&lt;/p&gt;

&lt;p&gt;And it is exactly the kind of decision an agent should surface instead of guessing.&lt;/p&gt;

&lt;p&gt;A good workflow should say:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;If the site depends on Wix CMS, Stores, Blog, or Forms, decide whether to migrate the data out or keep Wix as a backend before rebuilding those features.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is a much safer instruction than:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Convert Wix to React.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Verification matters more than generation
&lt;/h2&gt;

&lt;p&gt;The most dangerous part of this workflow is false confidence.&lt;/p&gt;

&lt;p&gt;The agent can generate a React app that looks convincing.&lt;/p&gt;

&lt;p&gt;But the migration is not done until the output is checked.&lt;/p&gt;

&lt;p&gt;A practical verification checklist should include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;every important URL has a matching route or redirect&lt;/li&gt;
&lt;li&gt;desktop and mobile layouts are checked&lt;/li&gt;
&lt;li&gt;images load from the right source&lt;/li&gt;
&lt;li&gt;navigation works&lt;/li&gt;
&lt;li&gt;forms submit somewhere real&lt;/li&gt;
&lt;li&gt;blog or CMS pages render from data&lt;/li&gt;
&lt;li&gt;metadata exists&lt;/li&gt;
&lt;li&gt;old URLs are mapped&lt;/li&gt;
&lt;li&gt;no obvious console errors appear&lt;/li&gt;
&lt;li&gt;performance is acceptable&lt;/li&gt;
&lt;li&gt;accessibility basics are not broken&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run build
npm run lint
npm run &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then check the running site:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And inspect actual pages in the browser.&lt;/p&gt;

&lt;p&gt;This is the same pattern I keep coming back to in agent workflows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;inspect -&amp;gt; decide -&amp;gt; run -&amp;gt; verify -&amp;gt; report
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code generation part is only one step.&lt;/p&gt;

&lt;p&gt;The verification is where the work becomes trustworthy.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where Terminal Skills fits
&lt;/h2&gt;

&lt;p&gt;This is why I like the Terminal Skills framing.&lt;/p&gt;

&lt;p&gt;The useful thing is not "AI can write React."&lt;/p&gt;

&lt;p&gt;We already know that.&lt;/p&gt;

&lt;p&gt;The useful thing is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI can follow a repeatable migration workflow if the workflow is packaged clearly enough.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;wix-to-react&lt;/code&gt; skill gives the agent a more specific operating path.&lt;/p&gt;

&lt;p&gt;It turns a vague request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Move my Wix site to React.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Into something closer to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Inventory the Wix site.
Classify static pages, CMS content, business logic, and SEO requirements.
Choose whether to migrate data or use Wix as a backend.
Rebuild the frontend in React or Next.js.
Verify routes, content, forms, metadata, and deployment readiness.
Report what was completed and what still needs human decisions.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is much better.&lt;/p&gt;

&lt;p&gt;It reduces the number of hidden assumptions.&lt;/p&gt;

&lt;p&gt;It also makes the agent easier to supervise.&lt;/p&gt;

&lt;p&gt;Instead of asking:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Did it convert the site?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can ask:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What pages did it inventory?
What content sources did it find?
Which Wix features still need a migration decision?
What routes were rebuilt?
What checks passed?
What is still missing?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those are better questions.&lt;/p&gt;

&lt;p&gt;They produce better work.&lt;/p&gt;




&lt;h2&gt;
  
  
  The agent should report gaps, not hide them
&lt;/h2&gt;

&lt;p&gt;One thing I would explicitly want in a Wix migration skill:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Do not pretend every Wix feature was migrated if it was only visually approximated.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This matters.&lt;/p&gt;

&lt;p&gt;If the old Wix site had a booking workflow and the new React app has a button that looks like "Book Now" but does nothing, that is not a migration.&lt;/p&gt;

&lt;p&gt;That is a visual placeholder.&lt;/p&gt;

&lt;p&gt;Placeholders are fine if they are labeled.&lt;/p&gt;

&lt;p&gt;They are dangerous if they are hidden.&lt;/p&gt;

&lt;p&gt;A good final report should say:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;rebuilt pages&lt;/li&gt;
&lt;li&gt;skipped pages&lt;/li&gt;
&lt;li&gt;assets copied&lt;/li&gt;
&lt;li&gt;data exported&lt;/li&gt;
&lt;li&gt;data not exported&lt;/li&gt;
&lt;li&gt;forms recreated&lt;/li&gt;
&lt;li&gt;forms still placeholder&lt;/li&gt;
&lt;li&gt;SEO mappings completed&lt;/li&gt;
&lt;li&gt;redirects still needed&lt;/li&gt;
&lt;li&gt;manual decisions required&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That kind of honesty is boring.&lt;/p&gt;

&lt;p&gt;It is also what makes agent work usable in production.&lt;/p&gt;




&lt;h2&gt;
  
  
  A realistic migration plan
&lt;/h2&gt;

&lt;p&gt;If I were using an agent for a Wix-to-React migration, I would want the workflow to look roughly like this.&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 1: Discovery
&lt;/h3&gt;

&lt;p&gt;Open the Wix site.&lt;/p&gt;

&lt;p&gt;Map the visible pages.&lt;/p&gt;

&lt;p&gt;Check navigation, footer links, sitemap if available, blog index, product pages, and any public routes.&lt;/p&gt;

&lt;p&gt;Create an inventory file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 2: Feature audit
&lt;/h3&gt;

&lt;p&gt;Identify whether the site uses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wix CMS&lt;/li&gt;
&lt;li&gt;Wix Blog&lt;/li&gt;
&lt;li&gt;Wix Stores&lt;/li&gt;
&lt;li&gt;Wix Bookings&lt;/li&gt;
&lt;li&gt;Wix Forms&lt;/li&gt;
&lt;li&gt;member login&lt;/li&gt;
&lt;li&gt;custom code&lt;/li&gt;
&lt;li&gt;third-party scripts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This decides how risky the migration is.&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 3: Content and asset extraction
&lt;/h3&gt;

&lt;p&gt;Download or document:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;images&lt;/li&gt;
&lt;li&gt;logos&lt;/li&gt;
&lt;li&gt;icons&lt;/li&gt;
&lt;li&gt;copy&lt;/li&gt;
&lt;li&gt;metadata&lt;/li&gt;
&lt;li&gt;blog content&lt;/li&gt;
&lt;li&gt;product data&lt;/li&gt;
&lt;li&gt;form fields&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not start rebuilding until the content source is clear.&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 4: React/Next.js rebuild
&lt;/h3&gt;

&lt;p&gt;Create the app structure.&lt;/p&gt;

&lt;p&gt;Build shared components.&lt;/p&gt;

&lt;p&gt;Recreate pages.&lt;/p&gt;

&lt;p&gt;Wire content.&lt;/p&gt;

&lt;p&gt;Add metadata.&lt;/p&gt;

&lt;p&gt;Add forms or placeholder warnings.&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 5: Verification
&lt;/h3&gt;

&lt;p&gt;Run build checks.&lt;/p&gt;

&lt;p&gt;Open pages locally.&lt;/p&gt;

&lt;p&gt;Compare important pages visually.&lt;/p&gt;

&lt;p&gt;Check mobile.&lt;/p&gt;

&lt;p&gt;Check forms.&lt;/p&gt;

&lt;p&gt;Check SEO metadata.&lt;/p&gt;

&lt;p&gt;Check old-to-new URL mapping.&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 6: Deployment readiness
&lt;/h3&gt;

&lt;p&gt;Prepare environment variables.&lt;/p&gt;

&lt;p&gt;Document backend dependencies.&lt;/p&gt;

&lt;p&gt;Write redirect rules.&lt;/p&gt;

&lt;p&gt;Create a final migration report.&lt;/p&gt;

&lt;p&gt;Only then should anyone talk about launch.&lt;/p&gt;




&lt;h2&gt;
  
  
  The bigger lesson
&lt;/h2&gt;

&lt;p&gt;Wix-to-React is a good example of where AI agent work is going.&lt;/p&gt;

&lt;p&gt;The value is not just producing code faster.&lt;/p&gt;

&lt;p&gt;The value is turning messy operational work into repeatable workflows.&lt;/p&gt;

&lt;p&gt;Most real tasks are not one command.&lt;/p&gt;

&lt;p&gt;They are sequences of judgment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;inspect the current system
understand what matters
choose the safest path
make the change
verify the result
explain the remaining risk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is true for video processing.&lt;/p&gt;

&lt;p&gt;It is true for deployment.&lt;/p&gt;

&lt;p&gt;It is true for content publishing.&lt;/p&gt;

&lt;p&gt;And it is definitely true for migrating a Wix site into React.&lt;/p&gt;

&lt;p&gt;The framework is not the hard part.&lt;/p&gt;

&lt;p&gt;The workflow is.&lt;/p&gt;

&lt;p&gt;That is why skills matter.&lt;/p&gt;

&lt;p&gt;Not because they make agents magical.&lt;/p&gt;

&lt;p&gt;Because they make agents less random.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;If you have a small Wix site and it still works, you may not need to migrate it.&lt;/p&gt;

&lt;p&gt;No-code tools are not automatically bad.&lt;/p&gt;

&lt;p&gt;But if your site has outgrown the builder, the migration needs to be treated like a real software project.&lt;/p&gt;

&lt;p&gt;Not a screenshot clone.&lt;/p&gt;

&lt;p&gt;Not a prompt.&lt;/p&gt;

&lt;p&gt;Not a one-click export fantasy.&lt;/p&gt;

&lt;p&gt;A workflow.&lt;/p&gt;

&lt;p&gt;That is the reason I like the &lt;code&gt;wix-to-react&lt;/code&gt; skill on Terminal Skills.&lt;/p&gt;

&lt;p&gt;It frames the job correctly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;inventory, classify, rebuild, verify, and report.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is how you move from "the agent made something that looks like my Wix site" to "the agent helped migrate the actual website."&lt;/p&gt;

&lt;p&gt;Explore the skill here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://terminalskills.io/skills/wix-to-react
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if you are building agent workflows around real work, not just demos, the broader Terminal Skills catalog is worth watching:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://terminalskills.io
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F51r7n7ciu3c39z0ibfb2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F51r7n7ciu3c39z0ibfb2.png" alt="Watercolor illustration of a website builder workflow becoming a structured React migration checklist" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>nextjs</category>
      <category>ai</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Solstice Cipher: a light-routing puzzle for the June Solstice Game Jam</title>
      <dc:creator>Alex Shev</dc:creator>
      <pubDate>Sun, 14 Jun 2026 15:41:40 +0000</pubDate>
      <link>https://dev.to/alexshev/solstice-cipher-a-light-routing-puzzle-for-the-june-solstice-game-jam-57lo</link>
      <guid>https://dev.to/alexshev/solstice-cipher-a-light-routing-puzzle-for-the-june-solstice-game-jam-57lo</guid>
      <description>&lt;p&gt;This is a submission for the &lt;a href="https://dev.to/challenges/june-game-jam-2026-06-03"&gt;June Solstice Game Jam&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Solstice Cipher&lt;/strong&gt; is a small browser puzzle game about the longest day, code-breaking, and the turning point between signal and shadow.&lt;/p&gt;

&lt;p&gt;The player rotates mirrors to route a solstice beam through every cipher node before landing on the final beacon. Each level is a tiny circuit of light: if the beam misses a cipher gate, the beacon does not unlock.&lt;/p&gt;

&lt;p&gt;The game is inspired by a few June themes from the challenge prompt:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the June solstice and the long arc of daylight&lt;/li&gt;
&lt;li&gt;light versus darkness&lt;/li&gt;
&lt;li&gt;turning points&lt;/li&gt;
&lt;li&gt;Alan Turing, code-breaking, and computational thinking&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Demo video: &lt;a href="https://desciple88.github.io/solstice-cipher-devto-game-jam/demo.html" rel="noopener noreferrer"&gt;watch in browser&lt;/a&gt; / &lt;a href="https://desciple88.github.io/solstice-cipher-devto-game-jam/demo.mp4" rel="noopener noreferrer"&gt;direct MP4&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Playable game: &lt;a href="https://desciple88.github.io/solstice-cipher-devto-game-jam/" rel="noopener noreferrer"&gt;https://desciple88.github.io/solstice-cipher-devto-game-jam/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Source code: &lt;a href="https://github.com/desciple88/solstice-cipher-devto-game-jam" rel="noopener noreferrer"&gt;https://github.com/desciple88/solstice-cipher-devto-game-jam&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;The game is a dependency-free HTML/CSS/JavaScript canvas app.&lt;/p&gt;

&lt;p&gt;The board is a 6x6 grid. A sunbeam enters from one side of the board, moves in one of four directions, and reflects when it hits a mirror:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/&lt;/code&gt; turns east to north, south to west, and so on&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;\&lt;/code&gt; turns east to south, north to west, and so on&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cipher nodes record whether the beam visited them. A level is solved only when the beam has touched all required cipher nodes and then reaches the beacon.&lt;/p&gt;

&lt;h2&gt;
  
  
  Controls
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Click or tap a mirror to rotate it.&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;Reset&lt;/strong&gt; or press &lt;code&gt;R&lt;/code&gt; to restart the level.&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;Next&lt;/strong&gt; or arrow keys to switch levels.&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;Hint&lt;/strong&gt; or press &lt;code&gt;H&lt;/code&gt; if the path gets stuck.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why the Turing Angle
&lt;/h2&gt;

&lt;p&gt;I wanted the Alan Turing category to feel like part of the mechanics, not just a label. The player is effectively debugging a simple signal machine: change one reflector, trace the path, see which gates activated, and iterate until the message resolves.&lt;/p&gt;

&lt;p&gt;It is not an Enigma simulator, but it borrows the feeling of signal routing, symbolic gates, and systematic code-breaking.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;HTML&lt;/li&gt;
&lt;li&gt;CSS&lt;/li&gt;
&lt;li&gt;JavaScript&lt;/li&gt;
&lt;li&gt;Canvas 2D&lt;/li&gt;
&lt;li&gt;ffmpeg for the demo capture&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI assistance was used while preparing the implementation and write-up. I am not entering this under the Best Google AI Usage category because I could not complete a real Google AI toolchain step during the build; the local Gemini CLI was unavailable in my environment.&lt;/p&gt;

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

&lt;p&gt;For a tiny jam game, the best scope was a mechanic that could be understood instantly: rotate mirrors, follow light, unlock the beacon.&lt;/p&gt;

&lt;p&gt;The solstice theme gave the visual direction. The Turing theme gave the rules: the path is not just pretty, it has to carry a complete signal.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>gamechallenge</category>
      <category>gamedev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>MCP Gives Your Agent Stripe Access. Skills Tell It What Not to Break.</title>
      <dc:creator>Alex Shev</dc:creator>
      <pubDate>Sun, 14 Jun 2026 13:10:19 +0000</pubDate>
      <link>https://dev.to/alexshev/mcp-gives-your-agent-stripe-access-skills-tell-it-what-not-to-break-1c90</link>
      <guid>https://dev.to/alexshev/mcp-gives-your-agent-stripe-access-skills-tell-it-what-not-to-break-1c90</guid>
      <description>&lt;p&gt;Stripe integrations are one of the places where AI coding agents look magical right up until they are dangerous.&lt;/p&gt;

&lt;p&gt;The agent can read docs.&lt;/p&gt;

&lt;p&gt;It can generate a checkout flow.&lt;/p&gt;

&lt;p&gt;It can wire a webhook.&lt;/p&gt;

&lt;p&gt;It can create a connected account, move money between a platform and a seller, and leave you with code that looks believable.&lt;/p&gt;

&lt;p&gt;That last part is the problem.&lt;/p&gt;

&lt;p&gt;Payments code does not fail like a todo app.&lt;/p&gt;

&lt;p&gt;If a todo app has a bad edge case, someone cannot mark a task complete.&lt;/p&gt;

&lt;p&gt;If a marketplace payment flow has a bad edge case, the wrong party collects fees, a seller cannot finish onboarding, a payout goes missing from your internal state, or a webhook retry silently creates a reconciliation mess.&lt;/p&gt;

&lt;p&gt;This is why I do not think "just connect the agent to Stripe MCP" is enough.&lt;/p&gt;

&lt;p&gt;MCP gives the agent access.&lt;/p&gt;

&lt;p&gt;A skill gives the agent a playbook.&lt;/p&gt;

&lt;h2&gt;
  
  
  The access layer: Stripe MCP
&lt;/h2&gt;

&lt;p&gt;Stripe has an MCP server for agentic workflows.&lt;/p&gt;

&lt;p&gt;That matters because an agent can work with Stripe through a structured tool surface instead of guessing from memory or copy-pasting stale snippets from the web.&lt;/p&gt;

&lt;p&gt;Stripe's own docs describe the MCP server as a set of tools agents can use to interact with the Stripe API and search Stripe's knowledge base.&lt;/p&gt;

&lt;p&gt;That is a real improvement over asking an LLM:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Build Stripe Connect for my marketplace"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and hoping it remembers the latest API shape.&lt;/p&gt;

&lt;p&gt;But access is not the same thing as judgment.&lt;/p&gt;

&lt;p&gt;If an agent has a Stripe tool, it still needs to know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;which Connect charge type fits the product model&lt;/li&gt;
&lt;li&gt;whether sellers need Express, full dashboard access, or a fully embedded flow&lt;/li&gt;
&lt;li&gt;where to store the connected account id&lt;/li&gt;
&lt;li&gt;which events must update internal order state&lt;/li&gt;
&lt;li&gt;when to use direct charges vs destination charges vs separate charges and transfers&lt;/li&gt;
&lt;li&gt;how to handle refunds, disputes, onboarding requirements, and payout status&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are not just API calls.&lt;/p&gt;

&lt;p&gt;They are product decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  The instruction layer: a Stripe Connect skill
&lt;/h2&gt;

&lt;p&gt;The latest Stripe-related skill I looked at on Terminal Skills is &lt;code&gt;stripe-connect&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It is built for marketplace and platform payments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;two-sided marketplaces&lt;/li&gt;
&lt;li&gt;seller/provider onboarding&lt;/li&gt;
&lt;li&gt;splitting payments between buyers and sellers&lt;/li&gt;
&lt;li&gt;platform fees&lt;/li&gt;
&lt;li&gt;payouts&lt;/li&gt;
&lt;li&gt;connected account management&lt;/li&gt;
&lt;li&gt;Connect webhooks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important detail is that the skill is not just a list of endpoints.&lt;/p&gt;

&lt;p&gt;It tells the agent how to reason through the flow.&lt;/p&gt;

&lt;p&gt;For example, the skill uses Stripe Accounts v2 for new Connect platforms. Instead of thinking in the old flat &lt;code&gt;type: "express"&lt;/code&gt; shape first, it frames a connected account around configurations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;merchant&lt;/code&gt; for accepting payments&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;recipient&lt;/code&gt; for receiving transfers and payouts&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;customer&lt;/code&gt; for being billed as a customer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the kind of detail an agent can easily miss if it is only pattern-matching from older examples.&lt;/p&gt;

&lt;p&gt;The skill also makes dashboard access explicit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;express&lt;/code&gt; for Stripe-hosted onboarding and dashboard&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;full&lt;/code&gt; for sellers who need a full Stripe dashboard or OAuth-style flow&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;none&lt;/code&gt; for embedded/custom platform control&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That distinction matters because onboarding is not just a technical step. It changes who owns UX, support, compliance surface, and seller control.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this belongs in a skill, not just a prompt
&lt;/h2&gt;

&lt;p&gt;You can tell an agent:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Use Stripe best practices."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That sounds clear.&lt;/p&gt;

&lt;p&gt;It is not.&lt;/p&gt;

&lt;p&gt;Best practices for what?&lt;/p&gt;

&lt;p&gt;A simple SaaS checkout?&lt;/p&gt;

&lt;p&gt;A usage-based subscription?&lt;/p&gt;

&lt;p&gt;A marketplace with sellers?&lt;/p&gt;

&lt;p&gt;A white-label platform?&lt;/p&gt;

&lt;p&gt;A service marketplace where money should be held until work is delivered?&lt;/p&gt;

&lt;p&gt;Those are different systems.&lt;/p&gt;

&lt;p&gt;A good skill narrows the task before code starts appearing.&lt;/p&gt;

&lt;p&gt;For Stripe Connect, I want the agent to ask and encode questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is the platform the merchant of record, or is the seller?&lt;/li&gt;
&lt;li&gt;Does the seller need dashboard access?&lt;/li&gt;
&lt;li&gt;Should the platform collect the fee at charge time?&lt;/li&gt;
&lt;li&gt;Is fulfillment immediate, delayed, or milestone-based?&lt;/li&gt;
&lt;li&gt;What internal state changes when onboarding completes?&lt;/li&gt;
&lt;li&gt;Which webhook events are the source of truth?&lt;/li&gt;
&lt;li&gt;What happens on refund, dispute, failed payment, and failed payout?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the work.&lt;/p&gt;

&lt;p&gt;The API call is the last mile.&lt;/p&gt;

&lt;h2&gt;
  
  
  The most useful part: choosing the charge model
&lt;/h2&gt;

&lt;p&gt;A lot of marketplace payment bugs start with choosing the wrong charge model.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;stripe-connect&lt;/code&gt; skill separates the main options:&lt;/p&gt;

&lt;h3&gt;
  
  
  Direct charges
&lt;/h3&gt;

&lt;p&gt;The charge happens on the connected account.&lt;/p&gt;

&lt;p&gt;This can make sense when the seller should own more of the payment relationship and see the charge directly in their Stripe account.&lt;/p&gt;

&lt;h3&gt;
  
  
  Destination charges
&lt;/h3&gt;

&lt;p&gt;The platform creates the charge and routes funds to the seller.&lt;/p&gt;

&lt;p&gt;This is often the clean marketplace default when the platform controls the buyer experience and collects an application fee.&lt;/p&gt;

&lt;h3&gt;
  
  
  Separate charges and transfers
&lt;/h3&gt;

&lt;p&gt;The platform charges the buyer first, then transfers funds later.&lt;/p&gt;

&lt;p&gt;This is the flexible option when delivery, risk, escrow-like timing, or multi-party routing matters.&lt;/p&gt;

&lt;p&gt;The agent needs to make this decision before it writes the PaymentIntent code.&lt;/p&gt;

&lt;p&gt;Otherwise it may produce code that works in a test card happy path but does not match the business.&lt;/p&gt;

&lt;h2&gt;
  
  
  Webhooks are where the integration becomes real
&lt;/h2&gt;

&lt;p&gt;Stripe integrations are not done when the payment succeeds in the browser.&lt;/p&gt;

&lt;p&gt;They are done when the backend state survives reality.&lt;/p&gt;

&lt;p&gt;That means webhooks.&lt;/p&gt;

&lt;p&gt;For Connect, the platform may need to listen for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;onboarding updates&lt;/li&gt;
&lt;li&gt;payment success and failure&lt;/li&gt;
&lt;li&gt;transfers&lt;/li&gt;
&lt;li&gt;payouts&lt;/li&gt;
&lt;li&gt;disputes&lt;/li&gt;
&lt;li&gt;connected-account events&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The skill calls out an easy-to-miss detail: Accounts v2 emits thin events through event destinations, and onboarding status can require listening for account requirements updates.&lt;/p&gt;

&lt;p&gt;That is exactly the kind of thing a generic prompt can skip.&lt;/p&gt;

&lt;p&gt;It may build the happy path and leave the operational path unfinished.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Stripe MCP and skills fit together
&lt;/h2&gt;

&lt;p&gt;The way I think about it:&lt;/p&gt;

&lt;p&gt;MCP is the tool socket.&lt;/p&gt;

&lt;p&gt;The skill is the operating procedure.&lt;/p&gt;

&lt;p&gt;Stripe MCP can let the agent query Stripe knowledge, inspect resources, and work through a structured API-facing interface.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;stripe-connect&lt;/code&gt; skill tells the agent how a marketplace payment system should be assembled:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;define the seller account model&lt;/li&gt;
&lt;li&gt;create the connected account&lt;/li&gt;
&lt;li&gt;generate onboarding&lt;/li&gt;
&lt;li&gt;store the account id&lt;/li&gt;
&lt;li&gt;choose the charge type&lt;/li&gt;
&lt;li&gt;collect platform fees intentionally&lt;/li&gt;
&lt;li&gt;wire webhooks&lt;/li&gt;
&lt;li&gt;handle refunds, disputes, and payouts&lt;/li&gt;
&lt;li&gt;test with Stripe CLI and test cards&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That is the difference between "agent can call Stripe" and "agent can build the right Stripe flow."&lt;/p&gt;

&lt;h2&gt;
  
  
  The agent should not be trusted with vague money movement
&lt;/h2&gt;

&lt;p&gt;This is the big lesson for me.&lt;/p&gt;

&lt;p&gt;AI agents are getting better at implementation.&lt;/p&gt;

&lt;p&gt;But money movement is not just implementation.&lt;/p&gt;

&lt;p&gt;It is policy, product design, compliance boundary, risk handling, and state reconciliation.&lt;/p&gt;

&lt;p&gt;So the workflow should look more 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;Human defines the marketplace model
        |
        v
Skill frames the Stripe Connect decisions
        |
        v
MCP/API tools give the agent current Stripe access
        |
        v
Agent writes the implementation
        |
        v
Tests + webhooks + review prove the money flow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the stack I trust more than a big prompt.&lt;/p&gt;

&lt;p&gt;Not "AI, build payments."&lt;/p&gt;

&lt;p&gt;"AI, follow this payment architecture, use current Stripe tools, and show me the decisions before you move money."&lt;/p&gt;

&lt;p&gt;That is where agents start becoming useful for serious backend work.&lt;/p&gt;

&lt;p&gt;Source:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Terminal Skills &lt;code&gt;stripe-connect&lt;/code&gt;: &lt;a href="https://terminalskills.io/skills/stripe-connect" rel="noopener noreferrer"&gt;https://terminalskills.io/skills/stripe-connect&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Stripe MCP docs: &lt;a href="https://docs.stripe.com/mcp" rel="noopener noreferrer"&gt;https://docs.stripe.com/mcp&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Stripe AI build docs: &lt;a href="https://docs.stripe.com/building-with-ai" rel="noopener noreferrer"&gt;https://docs.stripe.com/building-with-ai&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devtools</category>
      <category>ai</category>
      <category>stripe</category>
      <category>mcp</category>
    </item>
    <item>
      <title>Product Videos Should Be Build Artifacts, Not Manual Exports</title>
      <dc:creator>Alex Shev</dc:creator>
      <pubDate>Tue, 09 Jun 2026 19:42:24 +0000</pubDate>
      <link>https://dev.to/alexshev/product-videos-should-be-build-artifacts-not-manual-exports-d8i</link>
      <guid>https://dev.to/alexshev/product-videos-should-be-build-artifacts-not-manual-exports-d8i</guid>
      <description>&lt;p&gt;Every product launch needs the same small pile of video assets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a 16:9 demo clip for the launch page&lt;/li&gt;
&lt;li&gt;a square cut for social&lt;/li&gt;
&lt;li&gt;a GIF preview for the changelog&lt;/li&gt;
&lt;li&gt;a poster image for email&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The weird part is how often that still means opening a video editor by hand.&lt;/p&gt;

&lt;p&gt;Someone updates the product copy. Someone swaps the screen recording. Someone exports a new MP4. Someone crops another version. Then two weeks later the same release video cannot be reproduced exactly because the editor timeline, font version, plugin state, or export preset drifted.&lt;/p&gt;

&lt;p&gt;For product teams, that is the wrong abstraction.&lt;/p&gt;

&lt;p&gt;The launch video should be closer to a build artifact.&lt;/p&gt;

&lt;p&gt;Change the source. Open a PR. Let CI render the exact same video every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The useful idea: HTML as the video source
&lt;/h2&gt;

&lt;p&gt;Most product launch videos are not cinema.&lt;/p&gt;

&lt;p&gt;They are structured compositions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;headline&lt;/li&gt;
&lt;li&gt;short subcopy&lt;/li&gt;
&lt;li&gt;screen recording&lt;/li&gt;
&lt;li&gt;background audio&lt;/li&gt;
&lt;li&gt;a few transitions&lt;/li&gt;
&lt;li&gt;a logo or CTA&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That maps surprisingly well to HTML and CSS.&lt;/p&gt;

&lt;p&gt;Instead of keeping the source of truth in a visual editor, the source can live in a normal &lt;code&gt;index.html&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt;
  &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"stage"&lt;/span&gt;
  &lt;span class="na"&gt;data-composition-id=&lt;/span&gt;&lt;span class="s"&gt;"release-2-4"&lt;/span&gt;
  &lt;span class="na"&gt;data-start=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt;
  &lt;span class="na"&gt;data-width=&lt;/span&gt;&lt;span class="s"&gt;"1920"&lt;/span&gt;
  &lt;span class="na"&gt;data-height=&lt;/span&gt;&lt;span class="s"&gt;"1080"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;video&lt;/span&gt;
    &lt;span class="na"&gt;data-start=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt;
    &lt;span class="na"&gt;data-duration=&lt;/span&gt;&lt;span class="s"&gt;"8"&lt;/span&gt;
    &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"assets/screencast.mp4"&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;gt;&amp;lt;/video&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt;
    &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"headline"&lt;/span&gt;
    &lt;span class="na"&gt;data-start=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt;
    &lt;span class="na"&gt;data-duration=&lt;/span&gt;&lt;span class="s"&gt;"5"&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    v2.4 - Realtime Collaboration
  &lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt;
    &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"sub"&lt;/span&gt;
    &lt;span class="na"&gt;data-start=&lt;/span&gt;&lt;span class="s"&gt;"2"&lt;/span&gt;
    &lt;span class="na"&gt;data-duration=&lt;/span&gt;&lt;span class="s"&gt;"4"&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    Comment, mention, resolve - live.
  &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;audio&lt;/span&gt;
    &lt;span class="na"&gt;data-start=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt;
    &lt;span class="na"&gt;data-duration=&lt;/span&gt;&lt;span class="s"&gt;"8"&lt;/span&gt;
    &lt;span class="na"&gt;data-volume=&lt;/span&gt;&lt;span class="s"&gt;"0.7"&lt;/span&gt;
    &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"assets/bed.wav"&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;gt;&amp;lt;/audio&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That one file now carries things a video editor usually hides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;canvas size&lt;/li&gt;
&lt;li&gt;timing&lt;/li&gt;
&lt;li&gt;copy&lt;/li&gt;
&lt;li&gt;media references&lt;/li&gt;
&lt;li&gt;animation hooks&lt;/li&gt;
&lt;li&gt;composition id&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And because it is text, it can be reviewed like any other product change.&lt;/p&gt;

&lt;h2&gt;
  
  
  The important part is deterministic rendering
&lt;/h2&gt;

&lt;p&gt;Rendering HTML to video is only useful if the result is reproducible.&lt;/p&gt;

&lt;p&gt;If a CI job renders a different file every time, the system is just another flaky media tool.&lt;/p&gt;

&lt;p&gt;The better workflow is frame-seeking:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Load the HTML composition in headless Chrome.&lt;/li&gt;
&lt;li&gt;Seek to each timestamp.&lt;/li&gt;
&lt;li&gt;Capture the frame.&lt;/li&gt;
&lt;li&gt;Encode the frames into MP4.&lt;/li&gt;
&lt;li&gt;Produce the same output from the same source.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That is the reason HyperFrames is interesting here. It treats HTML, CSS, media, and seekable animation as a renderable video composition.&lt;/p&gt;

&lt;p&gt;Then FFmpeg handles the boring but necessary production work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# master render&lt;/span&gt;
npx hyperframes lint
npx hyperframes render

&lt;span class="c"&gt;# 1:1 social cut&lt;/span&gt;
ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; out/release-2-4.mp4 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"crop=1080:1080:420:0"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-c&lt;/span&gt;:a copy &lt;span class="se"&gt;\&lt;/span&gt;
  out/release-2-4-square.mp4

&lt;span class="c"&gt;# lightweight GIF for changelog&lt;/span&gt;
ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; out/release-2-4.mp4 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"fps=12,scale=640:-1:flags=lanczos"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  out/release-2-4.gif

&lt;span class="c"&gt;# poster frame for email&lt;/span&gt;
ffmpeg &lt;span class="nt"&gt;-ss&lt;/span&gt; 2 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-i&lt;/span&gt; out/release-2-4.mp4 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-frames&lt;/span&gt;:v 1 &lt;span class="se"&gt;\&lt;/span&gt;
  out/release-2-4-poster.jpg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One master render becomes every format the team needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why CI is the right place for this
&lt;/h2&gt;

&lt;p&gt;For a small SaaS team, the release note is already part of the engineering workflow.&lt;/p&gt;

&lt;p&gt;The video can be too.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Render launch video&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;v*"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;render&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;22"&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sudo apt-get update &amp;amp;&amp;amp; sudo apt-get install -y ffmpeg&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;working-directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;launch-video&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;npx hyperframes lint&lt;/span&gt;
          &lt;span class="s"&gt;npx hyperframes render&lt;/span&gt;
          &lt;span class="s"&gt;ffmpeg -i out/release-2-4.mp4 -vf "crop=1080:1080:420:0" -c:a copy out/square.mp4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/upload-artifact@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;launch-video&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;launch-video/out/*.mp4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the video is attached to the release process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;copy changes are visible in PRs&lt;/li&gt;
&lt;li&gt;timing changes are versioned&lt;/li&gt;
&lt;li&gt;release tags regenerate the same artifacts&lt;/li&gt;
&lt;li&gt;reviewers can inspect the rendered output&lt;/li&gt;
&lt;li&gt;social cuts come from the same master file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The team is not replacing creative work with CI.&lt;/p&gt;

&lt;p&gt;It is removing the repetitive export layer around a video that is mostly structured product information.&lt;/p&gt;

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

&lt;p&gt;This works best for videos that are template-driven:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;product launch clips&lt;/li&gt;
&lt;li&gt;changelog videos&lt;/li&gt;
&lt;li&gt;feature teasers&lt;/li&gt;
&lt;li&gt;onboarding explainers&lt;/li&gt;
&lt;li&gt;social demos&lt;/li&gt;
&lt;li&gt;doc/video snippets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is probably the wrong tool for a cinematic brand film.&lt;/p&gt;

&lt;p&gt;But most weekly product videos are not cinematic. They are release communication.&lt;/p&gt;

&lt;p&gt;And release communication should be repeatable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The agent angle
&lt;/h2&gt;

&lt;p&gt;The interesting part is what happens when an AI coding agent can edit the video source.&lt;/p&gt;

&lt;p&gt;An agent can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;update the release copy&lt;/li&gt;
&lt;li&gt;swap in a new screencast&lt;/li&gt;
&lt;li&gt;adjust timing&lt;/li&gt;
&lt;li&gt;add a maintained transition block&lt;/li&gt;
&lt;li&gt;run the lint step&lt;/li&gt;
&lt;li&gt;render the preview&lt;/li&gt;
&lt;li&gt;post-process the output&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is much more useful than asking an AI tool to generate a random video from a prompt.&lt;/p&gt;

&lt;p&gt;The agent is working inside the same system as the product team: files, PRs, CI, artifacts, and review.&lt;/p&gt;

&lt;p&gt;That is where AI video automation starts to feel practical.&lt;/p&gt;

&lt;p&gt;I wrote up the full workflow here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://terminalskills.io/use-cases/automate-product-videos-from-html" rel="noopener noreferrer"&gt;https://terminalskills.io/use-cases/automate-product-videos-from-html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The short version:&lt;/p&gt;

&lt;p&gt;If the video changes every release, put the video source next to the release.&lt;/p&gt;

&lt;p&gt;Then let the build system render it.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>cicd</category>
      <category>webdev</category>
      <category>html</category>
    </item>
    <item>
      <title>How to Write Terminal Skills That AI Agents Can Actually Use</title>
      <dc:creator>Alex Shev</dc:creator>
      <pubDate>Mon, 08 Jun 2026 21:07:58 +0000</pubDate>
      <link>https://dev.to/alexshev/how-to-write-terminal-skills-that-ai-agents-can-actually-use-2ll7</link>
      <guid>https://dev.to/alexshev/how-to-write-terminal-skills-that-ai-agents-can-actually-use-2ll7</guid>
      <description>&lt;p&gt;Most AI agent advice still sounds like prompt advice.&lt;/p&gt;

&lt;p&gt;Add more context.&lt;br&gt;
Write clearer instructions.&lt;br&gt;
Give the model examples.&lt;br&gt;
Use a better system prompt.&lt;/p&gt;

&lt;p&gt;That helps, but it misses the part that breaks in real work.&lt;/p&gt;

&lt;p&gt;The problem is not always that the agent does not know a command. The problem is that the agent does not know your workflow.&lt;/p&gt;

&lt;p&gt;It does not know when to inspect first.&lt;br&gt;
It does not know which defaults are safe.&lt;br&gt;
It does not know what "done" means.&lt;br&gt;
It does not know when to stop instead of guessing.&lt;br&gt;
It does not know which checks matter before something leaves the local machine.&lt;/p&gt;

&lt;p&gt;That is where Terminal Skills become useful.&lt;/p&gt;

&lt;p&gt;A Terminal Skill is not just a command shortcut. It is a small reusable operating procedure for an agent.&lt;/p&gt;

&lt;p&gt;It teaches:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;when to use a workflow&lt;/li&gt;
&lt;li&gt;what inputs are acceptable&lt;/li&gt;
&lt;li&gt;which commands or scripts are preferred&lt;/li&gt;
&lt;li&gt;what output should exist&lt;/li&gt;
&lt;li&gt;how to verify the result&lt;/li&gt;
&lt;li&gt;when to stop and ask for help&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last part is the difference between a useful agent workflow and a confident mess.&lt;/p&gt;

&lt;p&gt;Here is the pattern I use when writing one.&lt;/p&gt;
&lt;h2&gt;
  
  
  Start with the task, not the tool
&lt;/h2&gt;

&lt;p&gt;The easiest mistake is to begin with a tool name.&lt;/p&gt;

&lt;p&gt;Bad starting point:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Make an FFmpeg skill.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Better starting point:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Make a skill that turns a raw video file into an X-ready MP4, then verifies the upload is likely to work.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those are different scopes.&lt;/p&gt;

&lt;p&gt;The first one is a tool wrapper.&lt;/p&gt;

&lt;p&gt;The second one is a workflow.&lt;/p&gt;

&lt;p&gt;Agents do not need every possible FFmpeg flag. They need a stable path through a common problem.&lt;/p&gt;

&lt;p&gt;The same applies to any terminal workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;not "make a git skill"&lt;/li&gt;
&lt;li&gt;but "review a dirty worktree without touching unrelated user changes"&lt;/li&gt;
&lt;li&gt;not "make a deploy skill"&lt;/li&gt;
&lt;li&gt;but "deploy a Next.js app to Vercel and verify the live URL"&lt;/li&gt;
&lt;li&gt;not "make a search skill"&lt;/li&gt;
&lt;li&gt;but "inspect a repo and find the smallest safe file set for this task"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The more specific the workflow, the more useful the skill.&lt;/p&gt;

&lt;h2&gt;
  
  
  A useful skill has a contract
&lt;/h2&gt;

&lt;p&gt;I like thinking about a Terminal Skill as a contract between the human, the agent, and the machine.&lt;/p&gt;

&lt;p&gt;The contract says:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;If this kind of task appears,
and these inputs exist,
follow this workflow,
produce this output,
run these checks,
and stop under these conditions.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That sounds simple, but it removes a lot of randomness.&lt;/p&gt;

&lt;p&gt;Without a contract, the agent improvises.&lt;/p&gt;

&lt;p&gt;With a contract, the agent has a default operating path.&lt;/p&gt;

&lt;p&gt;That does not make the agent less intelligent. It makes the work less dependent on fresh reasoning every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The basic structure
&lt;/h2&gt;

&lt;p&gt;For most Terminal Skills, I would start with a folder 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;my-skill/
  SKILL.md
  scripts/
    run.sh
  examples/
    input-example.txt
  README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not every skill needs a script.&lt;/p&gt;

&lt;p&gt;Some skills are mostly procedural. Some are wrappers around existing CLIs. Some are just strong instructions plus verification commands.&lt;/p&gt;

&lt;p&gt;But the &lt;code&gt;SKILL.md&lt;/code&gt; is the important part.&lt;/p&gt;

&lt;p&gt;It should tell the agent how to work, not just what the tool does.&lt;/p&gt;

&lt;p&gt;Here is a practical template.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Skill Name&lt;/span&gt;

&lt;span class="gu"&gt;## Use When&lt;/span&gt;

Use this skill when the user asks to:
&lt;span class="p"&gt;-&lt;/span&gt; ...
&lt;span class="p"&gt;-&lt;/span&gt; ...

&lt;span class="gu"&gt;## Do Not Use When&lt;/span&gt;

Do not use this skill when:
&lt;span class="p"&gt;-&lt;/span&gt; ...
&lt;span class="p"&gt;-&lt;/span&gt; ...

&lt;span class="gu"&gt;## Inputs&lt;/span&gt;

Expected inputs:
&lt;span class="p"&gt;-&lt;/span&gt; source file or directory
&lt;span class="p"&gt;-&lt;/span&gt; target format
&lt;span class="p"&gt;-&lt;/span&gt; optional config

&lt;span class="gu"&gt;## Workflow&lt;/span&gt;
&lt;span class="p"&gt;
1.&lt;/span&gt; Inspect the input.
&lt;span class="p"&gt;2.&lt;/span&gt; Choose the smallest safe action.
&lt;span class="p"&gt;3.&lt;/span&gt; Run the script or command.
&lt;span class="p"&gt;4.&lt;/span&gt; Verify the output.
&lt;span class="p"&gt;5.&lt;/span&gt; Report the result with file paths and any warnings.

&lt;span class="gu"&gt;## Commands&lt;/span&gt;

&lt;span class="p"&gt;```&lt;/span&gt;&lt;span class="nl"&gt;bash
&lt;/span&gt;./scripts/run.sh input-file
&lt;span class="p"&gt;```&lt;/span&gt;

&lt;span class="gu"&gt;## Verification&lt;/span&gt;

Check:
&lt;span class="p"&gt;-&lt;/span&gt; output file exists
&lt;span class="p"&gt;-&lt;/span&gt; output format is correct
&lt;span class="p"&gt;-&lt;/span&gt; command exited successfully
&lt;span class="p"&gt;-&lt;/span&gt; logs contain no obvious errors

&lt;span class="gu"&gt;## Stop Conditions&lt;/span&gt;

Stop and ask the user if:
&lt;span class="p"&gt;-&lt;/span&gt; required input is missing
&lt;span class="p"&gt;-&lt;/span&gt; output validation fails
&lt;span class="p"&gt;-&lt;/span&gt; the task would publish, delete, charge, email, or deploy something
&lt;span class="p"&gt;-&lt;/span&gt; the command could overwrite user data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is already more useful than a loose prompt.&lt;/p&gt;

&lt;p&gt;It gives the agent a map.&lt;/p&gt;

&lt;h2&gt;
  
  
  The most important section is "Stop Conditions"
&lt;/h2&gt;

&lt;p&gt;Most people underwrite this part.&lt;/p&gt;

&lt;p&gt;They document the happy path and skip the failure boundaries.&lt;/p&gt;

&lt;p&gt;But agents need stop conditions badly.&lt;/p&gt;

&lt;p&gt;A good skill should say things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;stop if the repo has unrelated user changes&lt;/li&gt;
&lt;li&gt;stop if the API token is missing&lt;/li&gt;
&lt;li&gt;stop if the public page cannot be verified&lt;/li&gt;
&lt;li&gt;stop if the output file has no video stream&lt;/li&gt;
&lt;li&gt;stop if the command would delete or overwrite source files&lt;/li&gt;
&lt;li&gt;stop if the user approved a draft but did not approve publishing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where agent workflows become safer.&lt;/p&gt;

&lt;p&gt;For example, a social publishing skill should not only say:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Open the composer and publish the post.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It should say:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before posting, verify the composer contains the exact approved text.
After posting, verify the final permalink shows the full text and attached media.
If media is missing, do not report success.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is a real operating rule.&lt;/p&gt;

&lt;p&gt;It captures the part of the workflow that normally lives in someone's head.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verification should be concrete
&lt;/h2&gt;

&lt;p&gt;"Check that it worked" is not enough.&lt;/p&gt;

&lt;p&gt;A good Terminal Skill names the actual check.&lt;/p&gt;

&lt;p&gt;For a video skill:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffprobe &lt;span class="nt"&gt;-v&lt;/span&gt; error &lt;span class="nt"&gt;-show_streams&lt;/span&gt; &lt;span class="nt"&gt;-show_format&lt;/span&gt; output.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a code skill:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;test
&lt;/span&gt;git diff &lt;span class="nt"&gt;--check&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a content publishing skill:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Open the final live URL.
Confirm the title, body, tags, canonical URL, and media are visible.
Do not trust the editor preview as final verification.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a data export skill:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Check row count, headers, encoding, and sample records before sending the file.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agents are very good at saying "done" too early.&lt;/p&gt;

&lt;p&gt;Verification commands make "done" harder to fake.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the skill narrow
&lt;/h2&gt;

&lt;p&gt;The best skills are boringly specific.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;content-automation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;devto-draft-from-markdown
x-safe-video-export
reddit-comment-visibility-check
vercel-preview-deploy-and-verify
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Narrow skills have clearer triggers and fewer hidden assumptions.&lt;/p&gt;

&lt;p&gt;They are also easier to improve.&lt;/p&gt;

&lt;p&gt;If a video export fails, fix the video skill.&lt;br&gt;
If a DEV.to draft misses a canonical URL, fix the DEV.to skill.&lt;br&gt;
If a Reddit comment is visible to the owner but not public, fix the visibility check.&lt;/p&gt;

&lt;p&gt;One giant "content automation" skill would hide all of those failures inside one vague blob.&lt;/p&gt;

&lt;p&gt;Small skills make the workflow inspectable.&lt;/p&gt;
&lt;h2&gt;
  
  
  Use scripts for mechanics, instructions for judgment
&lt;/h2&gt;

&lt;p&gt;I do not think every skill should become a huge script.&lt;/p&gt;

&lt;p&gt;Scripts are good for mechanical repeatability:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;convert this file&lt;/li&gt;
&lt;li&gt;validate this JSON&lt;/li&gt;
&lt;li&gt;resize this image&lt;/li&gt;
&lt;li&gt;call this API&lt;/li&gt;
&lt;li&gt;generate this report&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instructions are better for judgment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;when to use the script&lt;/li&gt;
&lt;li&gt;which candidates to reject&lt;/li&gt;
&lt;li&gt;how to handle approval&lt;/li&gt;
&lt;li&gt;what counts as verification&lt;/li&gt;
&lt;li&gt;when not to continue&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The skill should combine both.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SKILL.md explains the workflow.
scripts/export.sh performs the conversion.
Verification commands prove the output.
Stop conditions prevent the agent from bluffing.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the useful shape.&lt;/p&gt;

&lt;p&gt;Not "the agent has a tool."&lt;/p&gt;

&lt;p&gt;"The agent has a way of working."&lt;/p&gt;

&lt;h2&gt;
  
  
  Example: a tiny repo-inspection skill
&lt;/h2&gt;

&lt;p&gt;Here is a small example that does not need a script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Repo Inspection&lt;/span&gt;

&lt;span class="gu"&gt;## Use When&lt;/span&gt;

Use this before editing an unfamiliar codebase.

&lt;span class="gu"&gt;## Workflow&lt;/span&gt;
&lt;span class="p"&gt;
1.&lt;/span&gt; Print the current directory.
&lt;span class="p"&gt;2.&lt;/span&gt; Check git status.
&lt;span class="p"&gt;3.&lt;/span&gt; List top-level files.
&lt;span class="p"&gt;4.&lt;/span&gt; Identify package/framework files.
&lt;span class="p"&gt;5.&lt;/span&gt; Search for relevant code with ripgrep.
&lt;span class="p"&gt;6.&lt;/span&gt; Read the smallest useful files before editing.

&lt;span class="gu"&gt;## Preferred Commands&lt;/span&gt;

&lt;span class="p"&gt;```&lt;/span&gt;&lt;span class="nl"&gt;bash
&lt;/span&gt;&lt;span class="nb"&gt;pwd
&lt;/span&gt;git status &lt;span class="nt"&gt;--short&lt;/span&gt;
rg &lt;span class="nt"&gt;--files&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-80&lt;/span&gt;
rg &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"keyword|component|route"&lt;/span&gt; .
&lt;span class="p"&gt;```&lt;/span&gt;

&lt;span class="gu"&gt;## Stop Conditions&lt;/span&gt;

Stop before editing if:
&lt;span class="p"&gt;-&lt;/span&gt; the user has unrelated changes in the target file
&lt;span class="p"&gt;-&lt;/span&gt; the task requires a destructive git command
&lt;span class="p"&gt;-&lt;/span&gt; the repo structure is unclear after inspection

&lt;span class="gu"&gt;## Verification&lt;/span&gt;

Before reporting done:
&lt;span class="p"&gt;-&lt;/span&gt; show changed files
&lt;span class="p"&gt;-&lt;/span&gt; run the smallest relevant test or check
&lt;span class="p"&gt;-&lt;/span&gt; explain any test that could not be run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not glamorous.&lt;/p&gt;

&lt;p&gt;But it prevents a lot of common agent mistakes.&lt;/p&gt;

&lt;p&gt;It teaches the agent the shape of careful work.&lt;/p&gt;

&lt;h2&gt;
  
  
  What makes a skill good?
&lt;/h2&gt;

&lt;p&gt;I usually judge a skill by five questions.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Does it have a clear trigger?
&lt;/h3&gt;

&lt;p&gt;The agent should know when to use it.&lt;/p&gt;

&lt;p&gt;If the trigger is vague, the skill will either be ignored or overused.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Does it reduce repeat reasoning?
&lt;/h3&gt;

&lt;p&gt;A good skill saves the agent from rediscovering the same workflow again.&lt;/p&gt;

&lt;p&gt;If the workflow is only used once, it may not need a skill yet.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Does it define done?
&lt;/h3&gt;

&lt;p&gt;The skill should say what output must exist and how to verify it.&lt;/p&gt;

&lt;p&gt;If "done" is subjective, the agent will guess.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Does it include stop conditions?
&lt;/h3&gt;

&lt;p&gt;This is the safety layer.&lt;/p&gt;

&lt;p&gt;The skill should prevent confident continuation when the workflow is missing a required input, external approval, or verification.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Is it small enough to maintain?
&lt;/h3&gt;

&lt;p&gt;If the skill becomes a giant manual for everything, it stops being useful.&lt;/p&gt;

&lt;p&gt;Small, composable skills are easier to trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bigger point
&lt;/h2&gt;

&lt;p&gt;AI agents are getting better at tool use.&lt;/p&gt;

&lt;p&gt;That does not mean every workflow should be improvised in chat.&lt;/p&gt;

&lt;p&gt;The more capable the agent becomes, the more important operating procedures become.&lt;/p&gt;

&lt;p&gt;Prompts are good for intent.&lt;br&gt;
Tools are good for capability.&lt;br&gt;
Skills are good for repeatable work.&lt;/p&gt;

&lt;p&gt;That is the layer I think more developers should build.&lt;/p&gt;

&lt;p&gt;Not because it is flashy.&lt;/p&gt;

&lt;p&gt;Because boring, reusable workflows are what turn agents from demos into something you can actually depend on.&lt;/p&gt;

&lt;p&gt;I am collecting more examples of this pattern at &lt;a href="https://terminalskills.io" rel="noopener noreferrer"&gt;Terminal Skills&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you are building your own agent workflows, start with one annoying task you repeat every week.&lt;/p&gt;

&lt;p&gt;Write down the trigger, workflow, verification, and stop conditions.&lt;/p&gt;

&lt;p&gt;That is your first skill.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>cli</category>
      <category>productivity</category>
      <category>devtools</category>
    </item>
  </channel>
</rss>
