<?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.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 Teaching Terminal Commands. Teach Terminal Workflows.</title>
      <dc:creator>Alex Shev</dc:creator>
      <pubDate>Mon, 01 Jun 2026 15:35:38 +0000</pubDate>
      <link>https://dev.to/alexshev/stop-teaching-terminal-commands-teach-terminal-workflows-n4p</link>
      <guid>https://dev.to/alexshev/stop-teaching-terminal-commands-teach-terminal-workflows-n4p</guid>
      <description>&lt;p&gt;Most terminal education teaches commands.&lt;/p&gt;

&lt;p&gt;That makes sense at the beginning.&lt;/p&gt;

&lt;p&gt;You need to know what &lt;code&gt;grep&lt;/code&gt; does. You need to know how &lt;code&gt;find&lt;/code&gt; works. You need to understand pipes, redirects, exit codes, environment variables, and shell scripts.&lt;/p&gt;

&lt;p&gt;But after a while, the command is not the hard part.&lt;/p&gt;

&lt;p&gt;The hard part is the workflow.&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 shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; &lt;span class="s2"&gt;"TODO"&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But:&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 repo.
Find the risky files.
Decide what needs changing.
Run the smallest useful command.
Verify the result.
Recover cleanly if the command was wrong.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the part most people are not taught.&lt;/p&gt;

&lt;p&gt;And it is also the part AI agents need most.&lt;/p&gt;




&lt;h2&gt;
  
  
  Commands are vocabulary
&lt;/h2&gt;

&lt;p&gt;Knowing terminal commands is useful.&lt;/p&gt;

&lt;p&gt;But commands are vocabulary.&lt;/p&gt;

&lt;p&gt;Workflows are how you actually get work done.&lt;/p&gt;

&lt;p&gt;A beginner asks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What command lists files?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A more experienced developer asks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What am I trying to learn from the filesystem, and what is the safest way to inspect it?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those are different questions.&lt;/p&gt;

&lt;p&gt;For example, this command is easy to memorize:&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="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the real workflow might be:&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="nb"&gt;pwd
ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt;
find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-maxdepth&lt;/span&gt; 2 &lt;span class="nt"&gt;-type&lt;/span&gt; f | &lt;span class="nb"&gt;head
&lt;/span&gt;git status &lt;span class="nt"&gt;--short&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That sequence tells you where you are, what is around you, what kind of project you are in, and whether the workspace is already dirty.&lt;/p&gt;

&lt;p&gt;The command is small.&lt;/p&gt;

&lt;p&gt;The judgment around the command is the skill.&lt;/p&gt;




&lt;h2&gt;
  
  
  A terminal workflow has stages
&lt;/h2&gt;

&lt;p&gt;I like this simple model:&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; recover
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That pattern shows up everywhere.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Inspect
&lt;/h3&gt;

&lt;p&gt;Before you change anything, learn the shape of the problem.&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="nb"&gt;pwd
&lt;/span&gt;git status &lt;span class="nt"&gt;--short&lt;/span&gt;
find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-maxdepth&lt;/span&gt; 2 &lt;span class="nt"&gt;-type&lt;/span&gt; f | &lt;span class="nb"&gt;sort&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-50&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not busywork.&lt;/p&gt;

&lt;p&gt;It prevents the most common terminal mistake: running the right command in the wrong place.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Decide
&lt;/h3&gt;

&lt;p&gt;Once you inspect, choose the smallest useful action.&lt;/p&gt;

&lt;p&gt;Do not start with the most powerful command.&lt;/p&gt;

&lt;p&gt;Start with the command that gives you more information or makes a reversible change.&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;git diff &lt;span class="nt"&gt;--&lt;/span&gt; path/to/file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nb"&gt;.&lt;/span&gt;
&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;ffprobe input.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; input.mp4 output.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Run
&lt;/h3&gt;

&lt;p&gt;Run the command with a clear expectation.&lt;/p&gt;

&lt;p&gt;You should know what success looks like before you press Enter.&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;Let's try this and see what happens.
&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;This should produce one MP4 in the output folder, keep the source file unchanged, and exit non-zero if the input is invalid.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Verify
&lt;/h3&gt;

&lt;p&gt;The command finishing is not the same as the workflow being done.&lt;/p&gt;

&lt;p&gt;If you converted a video, inspect the output.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffprobe output.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you changed code, run a relevant test.&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;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you edited content, check the final rendered page, not just the local markdown.&lt;/p&gt;

&lt;p&gt;Verification is where a terminal habit becomes a production workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Recover
&lt;/h3&gt;

&lt;p&gt;Every useful workflow needs a recovery path.&lt;/p&gt;

&lt;p&gt;What happens if the command fails?&lt;/p&gt;

&lt;p&gt;What happens if it succeeds but produces the wrong output?&lt;/p&gt;

&lt;p&gt;What happens if the workspace already had unrelated changes?&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;git diff
git restore &lt;span class="nt"&gt;--staged&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&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;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; output_failed
&lt;span class="nb"&gt;mv &lt;/span&gt;broken-output.mp4 output_failed/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Recovery should not be improvised after something breaks.&lt;/p&gt;

&lt;p&gt;It should be part of the workflow.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this matters more with AI agents
&lt;/h2&gt;

&lt;p&gt;AI agents are very good at discovering commands.&lt;/p&gt;

&lt;p&gt;They can usually find the right shell syntax faster than a human can.&lt;/p&gt;

&lt;p&gt;But they can still fail in familiar ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;running commands before inspecting the project&lt;/li&gt;
&lt;li&gt;using broad commands when a narrow one would do&lt;/li&gt;
&lt;li&gt;trusting success output too early&lt;/li&gt;
&lt;li&gt;overwriting files without a recovery plan&lt;/li&gt;
&lt;li&gt;skipping platform-specific verification&lt;/li&gt;
&lt;li&gt;treating a tool capability as a finished workflow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is why "give the agent terminal access" is not enough.&lt;/p&gt;

&lt;p&gt;Tool access gives the agent hands.&lt;/p&gt;

&lt;p&gt;The workflow tells the agent what careful work looks like.&lt;/p&gt;




&lt;h2&gt;
  
  
  Example: teaching &lt;code&gt;grep&lt;/code&gt; vs teaching search
&lt;/h2&gt;

&lt;p&gt;You can teach someone this:&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="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; &lt;span class="s2"&gt;"stripe"&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is a command.&lt;/p&gt;

&lt;p&gt;But a real search workflow might be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git status &lt;span class="nt"&gt;--short&lt;/span&gt;
find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-maxdepth&lt;/span&gt; 3 &lt;span class="nt"&gt;-type&lt;/span&gt; f | &lt;span class="nb"&gt;sort&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-100&lt;/span&gt;
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; &lt;span class="nt"&gt;--exclude-dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;node_modules &lt;span class="nt"&gt;--exclude-dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;.git &lt;span class="s2"&gt;"stripe"&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; &lt;span class="nt"&gt;--include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"*.ts"&lt;/span&gt; &lt;span class="nt"&gt;--include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"*.tsx"&lt;/span&gt; &lt;span class="s2"&gt;"createCheckout"&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The difference is not just syntax.&lt;/p&gt;

&lt;p&gt;The workflow says:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;check the workspace first&lt;/li&gt;
&lt;li&gt;avoid dependency folders&lt;/li&gt;
&lt;li&gt;search broadly, then narrow by file type&lt;/li&gt;
&lt;li&gt;search both product terms and implementation terms&lt;/li&gt;
&lt;li&gt;do not edit until you know where the real boundary is&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is what developers actually do.&lt;/p&gt;

&lt;p&gt;The command is only one piece.&lt;/p&gt;




&lt;h2&gt;
  
  
  Example: teaching &lt;code&gt;ffmpeg&lt;/code&gt; vs teaching media prep
&lt;/h2&gt;

&lt;p&gt;You can teach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; input.mov output.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;But if the file needs to be uploaded to a platform, the workflow matters more:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Inspect input.
Check duration, codec, pixel format, audio, and dimensions.
Convert to a safe default.
Inspect output.
Check file size.
Upload.
Verify the real platform preview.
Publish.
Verify the final post.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important lesson is not "use FFmpeg."&lt;/p&gt;

&lt;p&gt;The important lesson is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Never trust a media conversion until the destination platform accepts it.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is workflow knowledge.&lt;/p&gt;




&lt;h2&gt;
  
  
  This is where Terminal Skills fits
&lt;/h2&gt;

&lt;p&gt;Terminal Skills is useful because it gives agents a way to package workflows, not just commands.&lt;/p&gt;

&lt;p&gt;A good skill does 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;Run this command.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Use this when the task looks like this.
Inspect these inputs.
Run these steps.
Stop in these cases.
Verify these outputs.
Report the result in this format.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the missing layer between raw tool access and reliable automation.&lt;/p&gt;

&lt;p&gt;For example, a media skill can teach an agent how to prepare upload-safe video.&lt;/p&gt;

&lt;p&gt;A Git skill can teach an agent how to inspect a dirty worktree without destroying user changes.&lt;/p&gt;

&lt;p&gt;A deployment skill can teach an agent how to build, test, deploy, and verify a live URL.&lt;/p&gt;

&lt;p&gt;The point is not that the terminal becomes easier.&lt;/p&gt;

&lt;p&gt;The point is that the workflow becomes repeatable.&lt;/p&gt;




&lt;h2&gt;
  
  
  A useful skill has a definition of done
&lt;/h2&gt;

&lt;p&gt;This is the part I care about most.&lt;/p&gt;

&lt;p&gt;A command can finish successfully and still not solve the problem.&lt;/p&gt;

&lt;p&gt;A skill should define done.&lt;/p&gt;

&lt;p&gt;For a code change:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Done means the targeted files were changed, tests passed, no unrelated files were touched, and the result was summarized with exact file paths.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a video conversion:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Done means the output file is readable, uses the expected codec and pixel format, is under the target size, and has been accepted by the upload composer.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a content workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Done means the draft exists, the links work, the target platform format is respected, and publishing approval was recorded.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That last line matters.&lt;/p&gt;

&lt;p&gt;In real work, verification and approval are part of the system.&lt;/p&gt;

&lt;p&gt;They are not optional admin details.&lt;/p&gt;




&lt;h2&gt;
  
  
  The better way to teach terminal work
&lt;/h2&gt;

&lt;p&gt;I still think people should learn commands.&lt;/p&gt;

&lt;p&gt;But I would not stop there.&lt;/p&gt;

&lt;p&gt;Teach commands inside workflows.&lt;/p&gt;

&lt;p&gt;Instead of:&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 20 useful Linux commands.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Teach:&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 how to inspect an unfamiliar repo.
Here is how to safely search a codebase.
Here is how to prepare a video for upload.
Here is how to debug a broken script.
Here is how to verify a deployment.
Here is how to recover after a bad command.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is closer to how developers actually work.&lt;/p&gt;

&lt;p&gt;It is also closer to what AI agents need.&lt;/p&gt;

&lt;p&gt;Because the future of terminal automation is not agents memorizing more commands.&lt;/p&gt;

&lt;p&gt;It is agents following better workflows.&lt;/p&gt;




&lt;p&gt;If you are building with AI agents, ask this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What terminal task do I keep explaining from scratch?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;It is probably a workflow that should become a skill.&lt;/p&gt;

&lt;p&gt;Disclosure: I used AI assistance to draft and edit this article, then reviewed the examples, commands, and claims before publishing.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>cli</category>
      <category>devtools</category>
      <category>ai</category>
    </item>
    <item>
      <title>How I Made AI Video Uploads Boring with a Terminal Skill</title>
      <dc:creator>Alex Shev</dc:creator>
      <pubDate>Sat, 30 May 2026 23:18:20 +0000</pubDate>
      <link>https://dev.to/alexshev/how-i-made-ai-video-uploads-boring-with-a-terminal-skill-54pe</link>
      <guid>https://dev.to/alexshev/how-i-made-ai-video-uploads-boring-with-a-terminal-skill-54pe</guid>
      <description>&lt;p&gt;AI video demos are getting easier to generate.&lt;/p&gt;

&lt;p&gt;Publishing them is still weirdly fragile.&lt;/p&gt;

&lt;p&gt;Last week I had a simple task: take an AI-generated demo video, attach it to a post, and publish it without the platform silently dropping the media.&lt;/p&gt;

&lt;p&gt;The video looked fine locally.&lt;/p&gt;

&lt;p&gt;The upload did not.&lt;/p&gt;

&lt;p&gt;Wrong codec. Too large. Slow processing. Missing preview. No clear error. The browser said the upload was okay, but the composer did not actually register the file.&lt;/p&gt;

&lt;p&gt;That is the kind of problem I do not want to solve from memory at 11 PM.&lt;/p&gt;

&lt;p&gt;So I turned it into a Terminal Skill.&lt;/p&gt;

&lt;p&gt;Not a giant automation platform. Not a magic agent prompt. Just a small repeatable workflow that takes a messy video file and produces an X-safe default MP4 with checks before and after the conversion.&lt;/p&gt;

&lt;p&gt;Here is the use case.&lt;/p&gt;




&lt;h2&gt;
  
  
  The actual problem
&lt;/h2&gt;

&lt;p&gt;AI video tools often export files that are technically valid but awkward for social platforms.&lt;/p&gt;

&lt;p&gt;Common issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;file is too large&lt;/li&gt;
&lt;li&gt;codec is accepted by QuickTime but not by the platform&lt;/li&gt;
&lt;li&gt;pixel format is not &lt;code&gt;yuv420p&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;metadata is not optimized for web playback&lt;/li&gt;
&lt;li&gt;resolution is higher than needed&lt;/li&gt;
&lt;li&gt;audio track is missing or weird&lt;/li&gt;
&lt;li&gt;duration is fine visually but platform processing hangs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can fix most of this with FFmpeg.&lt;/p&gt;

&lt;p&gt;But the problem is not knowing that FFmpeg exists.&lt;/p&gt;

&lt;p&gt;The problem is remembering the exact flags, running them consistently, checking the output, and not trusting the browser upload until the platform shows a real preview.&lt;/p&gt;

&lt;p&gt;That is where a Terminal Skill helps.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I mean by a Terminal Skill
&lt;/h2&gt;

&lt;p&gt;For this workflow, a Terminal Skill is a small folder with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one script that does the conversion&lt;/li&gt;
&lt;li&gt;one validation step before conversion&lt;/li&gt;
&lt;li&gt;one validation step after conversion&lt;/li&gt;
&lt;li&gt;a short &lt;code&gt;SKILL.md&lt;/code&gt; explaining when to use it&lt;/li&gt;
&lt;li&gt;predictable input and output paths&lt;/li&gt;
&lt;li&gt;logs that make it obvious what happened&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important part is not the script itself.&lt;/p&gt;

&lt;p&gt;The important part is that the workflow becomes reusable by a human or an agent without rediscovering the rules every time.&lt;/p&gt;

&lt;p&gt;The skill answers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;When should I use this?
What input does it expect?
What output should it produce?
How do I know it worked?
When should I stop instead of publishing?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That last question matters a lot.&lt;/p&gt;

&lt;p&gt;For external platforms, "the command succeeded" is not the same as "the post is safe to publish."&lt;/p&gt;




&lt;h2&gt;
  
  
  The folder structure
&lt;/h2&gt;

&lt;p&gt;I kept the structure boring:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;x-safe-video/
  SKILL.md
  make-x-safe.sh
  examples/
  output/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script does the mechanical work.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;SKILL.md&lt;/code&gt; documents the operating rules:&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;# X-Safe Video&lt;/span&gt;

Use this when preparing generated video for X/Twitter upload.

Input:
&lt;span class="p"&gt;-&lt;/span&gt; MP4, MOV, or WebM
&lt;span class="p"&gt;-&lt;/span&gt; preferably under 2 minutes

Output:
&lt;span class="p"&gt;-&lt;/span&gt; MP4
&lt;span class="p"&gt;-&lt;/span&gt; H.264 video
&lt;span class="p"&gt;-&lt;/span&gt; AAC audio if audio exists
&lt;span class="p"&gt;-&lt;/span&gt; yuv420p pixel format
&lt;span class="p"&gt;-&lt;/span&gt; faststart metadata
&lt;span class="p"&gt;-&lt;/span&gt; scaled down if needed

Stop if:
&lt;span class="p"&gt;-&lt;/span&gt; ffprobe cannot read the file
&lt;span class="p"&gt;-&lt;/span&gt; output has no video stream
&lt;span class="p"&gt;-&lt;/span&gt; output is larger than the target platform limit
&lt;span class="p"&gt;-&lt;/span&gt; upload composer does not show a real video preview
&lt;span class="p"&gt;-&lt;/span&gt; platform does not show Uploaded 100%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the difference between a script and a skill.&lt;/p&gt;

&lt;p&gt;A script says:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Run this command.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A skill says:&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 workflow, the boundary, and the definition of done.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The conversion script
&lt;/h2&gt;

&lt;p&gt;Here is the simplified version.&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;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;INPUT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;:?Usage:&lt;span class="p"&gt; ./make-x-safe.sh input-video&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;OUTDIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OUTDIR&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="p"&gt;./output&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OUTDIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$INPUT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Input file not found: &lt;/span&gt;&lt;span class="nv"&gt;$INPUT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nv"&gt;BASENAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;basename&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$INPUT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASENAME&lt;/span&gt;&lt;span class="p"&gt;%.*&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;OUTPUT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OUTDIR&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_x_safe.mp4"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Inspecting input..."&lt;/span&gt;
ffprobe &lt;span class="nt"&gt;-v&lt;/span&gt; error &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-select_streams&lt;/span&gt; v:0 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-show_entries&lt;/span&gt; &lt;span class="nv"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;codec_name,width,height,pix_fmt,duration &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-of&lt;/span&gt; &lt;span class="nv"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;noprint_wrappers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$INPUT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Converting to X-safe MP4..."&lt;/span&gt;
ffmpeg &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$INPUT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"scale='min(1280,iw)':-2"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-c&lt;/span&gt;:v libx264 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-profile&lt;/span&gt;:v high &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-pix_fmt&lt;/span&gt; yuv420p &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-preset&lt;/span&gt; medium &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-crf&lt;/span&gt; 23 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-movflags&lt;/span&gt; +faststart &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-c&lt;/span&gt;:a aac &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-b&lt;/span&gt;:a 128k &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OUTPUT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Inspecting output..."&lt;/span&gt;
ffprobe &lt;span class="nt"&gt;-v&lt;/span&gt; error &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-select_streams&lt;/span&gt; v:0 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-show_entries&lt;/span&gt; &lt;span class="nv"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;codec_name,width,height,pix_fmt,duration &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-of&lt;/span&gt; &lt;span class="nv"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;noprint_wrappers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OUTPUT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nv"&gt;BYTES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &amp;lt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OUTPUT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;MB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;BYTES &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="m"&gt;1024&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="m"&gt;1024&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Output: &lt;/span&gt;&lt;span class="nv"&gt;$OUTPUT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Size: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MB&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;MB"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not the most advanced FFmpeg command in the world.&lt;/p&gt;

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

&lt;p&gt;The goal is not to make the cleverest media pipeline. The goal is to make a reliable default that works under pressure.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why these flags matter
&lt;/h2&gt;

&lt;p&gt;The important pieces:&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="nt"&gt;-c&lt;/span&gt;:v libx264
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;H.264 is still the safest default for social uploads.&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="nt"&gt;-pix_fmt&lt;/span&gt; yuv420p
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This avoids the classic "works locally, fails elsewhere" problem with pixel formats.&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="nt"&gt;-movflags&lt;/span&gt; +faststart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This moves metadata to the beginning of the file so web playback can start faster.&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="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"scale='min(1280,iw)':-2"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This keeps smaller videos unchanged and scales oversized ones down to a practical width.&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="nt"&gt;-crf&lt;/span&gt; 23
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Good enough quality without creating a monster file.&lt;/p&gt;

&lt;p&gt;Could I tune this per video? Yes.&lt;/p&gt;

&lt;p&gt;Do I want to think about that every time I need to publish a 20-second AI demo? No.&lt;/p&gt;




&lt;h2&gt;
  
  
  The verification step is the real skill
&lt;/h2&gt;

&lt;p&gt;The conversion is only half the workflow.&lt;/p&gt;

&lt;p&gt;The platform check matters more.&lt;/p&gt;

&lt;p&gt;My rule now:&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 trust "upload succeeded."
Trust only the composer state.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For an AI video post, I want to see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;video preview visible&lt;/li&gt;
&lt;li&gt;upload progress completed&lt;/li&gt;
&lt;li&gt;platform disclosure selected if needed&lt;/li&gt;
&lt;li&gt;post button enabled&lt;/li&gt;
&lt;li&gt;final published post shows the video&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the browser automation says the file was uploaded but the composer does not show the video, the workflow stops.&lt;/p&gt;

&lt;p&gt;That sounds obvious, but this is where a lot of automation breaks.&lt;/p&gt;

&lt;p&gt;It checks the API call or file input state, not the actual user-facing publishing state.&lt;/p&gt;

&lt;p&gt;The skill's job is to keep that distinction explicit.&lt;/p&gt;




&lt;h2&gt;
  
  
  Making it agent-friendly
&lt;/h2&gt;

&lt;p&gt;The next step is making the workflow easy for an AI agent to use.&lt;/p&gt;

&lt;p&gt;That means the skill needs plain instructions:&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="gu"&gt;## Agent Instructions&lt;/span&gt;
&lt;span class="p"&gt;
1.&lt;/span&gt; Run &lt;span class="sb"&gt;`./make-x-safe.sh &amp;lt;video&amp;gt;`&lt;/span&gt;.
&lt;span class="p"&gt;2.&lt;/span&gt; Read the output path from stdout.
&lt;span class="p"&gt;3.&lt;/span&gt; Confirm &lt;span class="sb"&gt;`ffprobe`&lt;/span&gt; shows:
&lt;span class="p"&gt;   -&lt;/span&gt; codec_name=h264
&lt;span class="p"&gt;   -&lt;/span&gt; pix_fmt=yuv420p
&lt;span class="p"&gt;4.&lt;/span&gt; Check file size.
&lt;span class="p"&gt;5.&lt;/span&gt; Upload through the real platform composer.
&lt;span class="p"&gt;6.&lt;/span&gt; Verify visual preview before posting.
&lt;span class="p"&gt;7.&lt;/span&gt; After posting, open the final URL and verify the video is embedded.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice what is missing:&lt;/p&gt;

&lt;p&gt;No vague "make it work."&lt;/p&gt;

&lt;p&gt;No "post when ready."&lt;/p&gt;

&lt;p&gt;No giant prompt with 40 edge cases.&lt;/p&gt;

&lt;p&gt;The skill gives the agent a small operating procedure with a clear stop condition.&lt;/p&gt;

&lt;p&gt;That is much easier to trust.&lt;/p&gt;




&lt;h2&gt;
  
  
  What changed
&lt;/h2&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Generate video.
Try upload.
Watch it fail.
Search old commands.
Re-encode.
Try again.
Hope the preview appears.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Generate video.
Run one command.
Check output.
Upload.
Verify preview.
Publish.
Verify final post.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The workflow is not glamorous.&lt;/p&gt;

&lt;p&gt;It is better than glamorous: it is boring.&lt;/p&gt;

&lt;p&gt;And boring is what I want from production media prep.&lt;/p&gt;




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

&lt;p&gt;This is why I keep coming back to Terminal Skills.&lt;/p&gt;

&lt;p&gt;A useful AI workflow is usually not one huge autonomous agent.&lt;/p&gt;

&lt;p&gt;It is a set of small, documented, reusable capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;prepare a video for upload&lt;/li&gt;
&lt;li&gt;inspect a repo&lt;/li&gt;
&lt;li&gt;generate thumbnails&lt;/li&gt;
&lt;li&gt;validate a draft&lt;/li&gt;
&lt;li&gt;resize images&lt;/li&gt;
&lt;li&gt;check links&lt;/li&gt;
&lt;li&gt;publish only after approval&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each skill removes one fragile piece of manual memory.&lt;/p&gt;

&lt;p&gt;Each skill gives the agent a narrower job.&lt;/p&gt;

&lt;p&gt;Each skill creates a cleaner definition of done.&lt;/p&gt;

&lt;p&gt;That is the part I think a lot of AI tooling conversations miss.&lt;/p&gt;

&lt;p&gt;The future is not just "agents can use tools."&lt;/p&gt;

&lt;p&gt;The useful version is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agents can use well-defined skills with clear boundaries.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is how the work becomes repeatable.&lt;/p&gt;

&lt;p&gt;And for AI video uploads, repeatable beats clever every time.&lt;/p&gt;




&lt;p&gt;If you build with AI agents, what is the workflow you keep fixing manually?&lt;/p&gt;

&lt;p&gt;That is probably your next Terminal Skill.&lt;/p&gt;

&lt;p&gt;Disclosure: I used AI assistance to draft and edit this article, then reviewed the workflow, commands, and claims before publishing.&lt;/p&gt;

</description>
      <category>ffmpeg</category>
      <category>ai</category>
      <category>cli</category>
      <category>devtools</category>
    </item>
    <item>
      <title>Approval Gates for AI Agents: Draft Approval Is Not Publish Approval</title>
      <dc:creator>Alex Shev</dc:creator>
      <pubDate>Wed, 27 May 2026 16:52:45 +0000</pubDate>
      <link>https://dev.to/alexshev/approval-gates-for-ai-agents-draft-approval-is-not-publish-approval-2ap5</link>
      <guid>https://dev.to/alexshev/approval-gates-for-ai-agents-draft-approval-is-not-publish-approval-2ap5</guid>
      <description>&lt;p&gt;One of the easiest ways to make an AI agent dangerous is to give it a vague approval.&lt;/p&gt;

&lt;p&gt;Not because the agent is malicious.&lt;/p&gt;

&lt;p&gt;Because humans use words like "ok", "approved", and "ship it" casually.&lt;/p&gt;

&lt;p&gt;In a normal conversation, that is fine. In an automated workflow, it can become a bug.&lt;/p&gt;

&lt;p&gt;If an agent is drafting an article, writing a tweet, preparing a pull request, generating social posts, or touching an external platform, the question is not just:&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 human approve this?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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 did the human approve?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That distinction matters more than most agent tooling discussions admit.&lt;/p&gt;




&lt;h2&gt;
  
  
  The small approval bug that becomes a big workflow problem
&lt;/h2&gt;

&lt;p&gt;Imagine this simple flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An agent prepares 10 social posts.&lt;/li&gt;
&lt;li&gt;The human says "looks good".&lt;/li&gt;
&lt;li&gt;The agent publishes all 10 immediately.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Maybe that was correct.&lt;/p&gt;

&lt;p&gt;Maybe it was not.&lt;/p&gt;

&lt;p&gt;The human might have meant:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The copy looks good.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent interpreted it as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Publish everything now.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is not a model intelligence problem. It is a workflow design problem.&lt;/p&gt;

&lt;p&gt;When an action leaves the local workspace, ambiguity gets expensive.&lt;/p&gt;

&lt;p&gt;Publishing, emailing, commenting, deploying, charging a card, posting to social media, and modifying production systems should not depend on a loose interpretation of "ok."&lt;/p&gt;

&lt;p&gt;They need explicit gates.&lt;/p&gt;




&lt;h2&gt;
  
  
  The approval types I separate now
&lt;/h2&gt;

&lt;p&gt;For agent workflows, I like separating approval into at least four different meanings.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Approval to draft
&lt;/h3&gt;

&lt;p&gt;This means:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Yes, prepare the thing.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent can research, outline, write, generate assets, create local files, and prepare a proposal.&lt;/p&gt;

&lt;p&gt;But it cannot publish.&lt;/p&gt;

&lt;p&gt;This is the safest default for content work.&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;Prepare a DEV.to draft about approval gates.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That should create a local markdown draft or an unpublished draft, depending on the workflow.&lt;/p&gt;

&lt;p&gt;It should not post the article publicly.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Approval of the draft
&lt;/h3&gt;

&lt;p&gt;This means:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The content direction is acceptable.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The human may be approving the argument, the structure, the tone, or the asset selection.&lt;/p&gt;

&lt;p&gt;But that still does not automatically mean:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Publish it right now.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is where many agent systems get sloppy.&lt;/p&gt;

&lt;p&gt;Draft approval is not publish approval.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Approval to publish
&lt;/h3&gt;

&lt;p&gt;This needs to be explicit.&lt;/p&gt;

&lt;p&gt;The agent should know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what platform&lt;/li&gt;
&lt;li&gt;what asset or draft&lt;/li&gt;
&lt;li&gt;whether to publish now or schedule&lt;/li&gt;
&lt;li&gt;whether comments/replies/source attribution are included&lt;/li&gt;
&lt;li&gt;whether the approval applies to one post or a batch&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 plaintext"&gt;&lt;code&gt;Publish this DEV.to article now.
&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;Post only the first X drafts, with the source as the first reply.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is much safer than letting the agent infer a public action from a vague "ok."&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Approval for automation reminders
&lt;/h3&gt;

&lt;p&gt;This one is subtle.&lt;/p&gt;

&lt;p&gt;A reminder or cron job should often prepare work, not perform external actions.&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;Every morning, find 3 candidate topics and ask me which one to use.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is different from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Every morning, publish a post.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first one keeps the human in the loop.&lt;/p&gt;

&lt;p&gt;The second one creates a recurring external action, which is much riskier.&lt;/p&gt;

&lt;p&gt;Most teams should start with reminder-based automation before action-based automation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this matters for CLI and agent workflows
&lt;/h2&gt;

&lt;p&gt;CLI workflows make this even more important because agents can act fast.&lt;/p&gt;

&lt;p&gt;A coding agent can edit files, run scripts, create branches, call APIs, deploy apps, write comments, and open browser sessions.&lt;/p&gt;

&lt;p&gt;That speed is useful only if the boundaries are clear.&lt;/p&gt;

&lt;p&gt;The workflow should define what the agent may do locally without asking and what requires a human gate.&lt;/p&gt;

&lt;p&gt;For example, I am comfortable letting an agent do this freely:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;inspect a repo&lt;/li&gt;
&lt;li&gt;write a local draft&lt;/li&gt;
&lt;li&gt;run tests&lt;/li&gt;
&lt;li&gt;generate local assets&lt;/li&gt;
&lt;li&gt;prepare a post&lt;/li&gt;
&lt;li&gt;create a report&lt;/li&gt;
&lt;li&gt;summarize findings&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I want a stronger gate before this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;publish to DEV.to&lt;/li&gt;
&lt;li&gt;post on X&lt;/li&gt;
&lt;li&gt;send email&lt;/li&gt;
&lt;li&gt;comment on Reddit&lt;/li&gt;
&lt;li&gt;deploy to production&lt;/li&gt;
&lt;li&gt;spend money&lt;/li&gt;
&lt;li&gt;modify customer data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The difference is not whether the agent is capable.&lt;/p&gt;

&lt;p&gt;The difference is whether the action is reversible, private, and low-risk.&lt;/p&gt;

&lt;p&gt;Local work is cheap to revise.&lt;/p&gt;

&lt;p&gt;External work creates a public or operational footprint.&lt;/p&gt;




&lt;h2&gt;
  
  
  A simple pattern: declare the gate in the task
&lt;/h2&gt;

&lt;p&gt;One practical fix is to write the gate directly into the task.&lt;/p&gt;

&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Write an article about approval gates.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Prepare a local draft only. Do not publish. Return the file path and wait for explicit publish approval.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Make comments for Reddit.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Prepare comment drafts only. Do not post. Recommend the safest first set and wait for approval.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Deploy this.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use:&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 preview deployment first. Do not promote to production until I explicitly approve production.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sounds boring, but boring is good here.&lt;/p&gt;

&lt;p&gt;Good agent workflows are often just normal operational discipline written down clearly enough that the agent cannot guess wrong.&lt;/p&gt;

&lt;p&gt;If the workflow supports metadata, make the gate machine-readable:&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;gate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;draft_only&lt;/span&gt;
&lt;span class="na"&gt;external_actions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="na"&gt;next_approval_required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;publish_to_devto&lt;/span&gt;
&lt;span class="na"&gt;scope&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;single_article&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That tiny block is not bureaucracy. It gives the agent a state it can report, verify, and refuse to exceed.&lt;/p&gt;




&lt;h2&gt;
  
  
  The agent should report its current gate
&lt;/h2&gt;

&lt;p&gt;The agent should also say what state the work is in.&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;Status: local draft only.
No external publication happened.
Next gate: human approval to publish.
&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;Status: posted.
Verified final URL.
No additional replies published.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes the workflow auditable.&lt;/p&gt;

&lt;p&gt;It also prevents the human from having to infer what happened.&lt;/p&gt;

&lt;p&gt;When agents are doing real work, "done" is not enough.&lt;/p&gt;

&lt;p&gt;The agent should report:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what changed&lt;/li&gt;
&lt;li&gt;where the artifact is&lt;/li&gt;
&lt;li&gt;what was verified&lt;/li&gt;
&lt;li&gt;what did not happen&lt;/li&gt;
&lt;li&gt;what approval is needed next&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Good agents should not only complete tasks. They should make the boundary of the next task clear.&lt;/p&gt;




&lt;h2&gt;
  
  
  Batch work needs an even stronger gate
&lt;/h2&gt;

&lt;p&gt;Batch publishing is where approval ambiguity gets especially risky.&lt;/p&gt;

&lt;p&gt;If an agent prepares 25 comments, does approval mean:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;publish all 25 now?&lt;/li&gt;
&lt;li&gt;publish the safest 5?&lt;/li&gt;
&lt;li&gt;publish one per day?&lt;/li&gt;
&lt;li&gt;publish only after checking each target again?&lt;/li&gt;
&lt;li&gt;publish drafts after human edits?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are very different actions.&lt;/p&gt;

&lt;p&gt;For batch workflows, I like adding two fields:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Approval scope:
Cadence decision:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Approval scope: first 5 comments only
Cadence decision: publish today, one by one, stop on warning
&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;Approval scope: all 10 posts approved as drafts
Cadence decision: schedule one per day at 10 AM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That tiny bit of structure prevents a lot of mistakes.&lt;/p&gt;

&lt;p&gt;It also gives the agent a concrete stop condition.&lt;/p&gt;




&lt;h2&gt;
  
  
  This belongs inside skills
&lt;/h2&gt;

&lt;p&gt;This is one reason I care about reusable agent skills.&lt;/p&gt;

&lt;p&gt;A 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;Here is how to perform the task.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It should also say:&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 what requires approval.
Here is what can be done locally.
Here is how to verify the result.
Here is when to stop.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;A tool gives the agent power.&lt;/p&gt;

&lt;p&gt;A skill gives the agent operating rules.&lt;/p&gt;

&lt;p&gt;It can encode approval gates as reusable policy, not just task steps.&lt;/p&gt;

&lt;p&gt;For example, a publishing skill should define:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;draft-only mode&lt;/li&gt;
&lt;li&gt;review mode&lt;/li&gt;
&lt;li&gt;publish mode&lt;/li&gt;
&lt;li&gt;source/comment behavior&lt;/li&gt;
&lt;li&gt;verification steps&lt;/li&gt;
&lt;li&gt;rollback or correction process&lt;/li&gt;
&lt;li&gt;rate-limit and spam-warning stop conditions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without that, the agent has to infer the process from the conversation.&lt;/p&gt;

&lt;p&gt;That is exactly where mistakes happen.&lt;/p&gt;




&lt;h2&gt;
  
  
  The rule I use
&lt;/h2&gt;

&lt;p&gt;My current rule is simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If the action is external, public, paid, destructive, or hard to undo, the approval must name the action.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;"Looks good" is enough for a draft.&lt;/p&gt;

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

&lt;p&gt;"Ok" is enough to continue local work.&lt;/p&gt;

&lt;p&gt;It is not enough to spend money, post publicly, email someone, or modify production.&lt;/p&gt;

&lt;p&gt;For those actions, the approval should be explicit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Publish this now.
Send this email.
Deploy to production.
Post these 5 comments.
Charge this card.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal is not to slow the agent down.&lt;/p&gt;

&lt;p&gt;The goal is to make speed safe.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;The fix is not complicated: write the gates down.&lt;/p&gt;

&lt;p&gt;Make the agent report which gate it is at.&lt;/p&gt;

&lt;p&gt;And never let draft approval silently become publish approval.&lt;/p&gt;




&lt;p&gt;I am collecting and building practical examples of this kind of agent workflow discipline at &lt;a href="https://terminalskills.io/" rel="noopener noreferrer"&gt;Terminal Skills&lt;/a&gt;: reusable skills that teach agents not only which tools to use, but how to work safely and repeatably.&lt;/p&gt;

&lt;p&gt;Disclosure: I used AI assistance while drafting this article, then reviewed and edited it manually.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>ai</category>
      <category>automation</category>
      <category>devtools</category>
    </item>
    <item>
      <title>MCP Gave AI Agents Tools. A2A Gives Them Coworkers.</title>
      <dc:creator>Alex Shev</dc:creator>
      <pubDate>Mon, 25 May 2026 15:30:15 +0000</pubDate>
      <link>https://dev.to/alexshev/mcp-gave-ai-agents-tools-a2a-gives-them-coworkers-dp0</link>
      <guid>https://dev.to/alexshev/mcp-gave-ai-agents-tools-a2a-gives-them-coworkers-dp0</guid>
      <description>&lt;p&gt;Most AI agent conversations eventually run into the same question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What happens when one agent is not enough?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A single agent can write code, search docs, run tests, call APIs, summarize files, and generate reports.&lt;/p&gt;

&lt;p&gt;That already feels useful.&lt;/p&gt;

&lt;p&gt;But real work rarely fits into one neat box.&lt;/p&gt;

&lt;p&gt;A software project might need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one agent to research requirements&lt;/li&gt;
&lt;li&gt;one agent to write code&lt;/li&gt;
&lt;li&gt;one agent to generate tests&lt;/li&gt;
&lt;li&gt;one agent to review the result&lt;/li&gt;
&lt;li&gt;one agent to deploy or monitor the system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A customer support workflow might need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a billing agent&lt;/li&gt;
&lt;li&gt;a technical support agent&lt;/li&gt;
&lt;li&gt;a sales agent&lt;/li&gt;
&lt;li&gt;a human handoff agent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A content workflow might need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a research agent&lt;/li&gt;
&lt;li&gt;a writing agent&lt;/li&gt;
&lt;li&gt;an SEO agent&lt;/li&gt;
&lt;li&gt;an editor&lt;/li&gt;
&lt;li&gt;a publishing assistant&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At that point, the interesting problem is no longer just:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can an agent use a tool?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It becomes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can agents work with each other?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is where the &lt;strong&gt;A2A protocol&lt;/strong&gt; becomes interesting.&lt;/p&gt;

&lt;p&gt;And that is why the &lt;code&gt;a2a-protocol&lt;/code&gt; skill on Terminal Skills is worth looking at.&lt;/p&gt;




&lt;h2&gt;
  
  
  MCP vs A2A in one sentence
&lt;/h2&gt;

&lt;p&gt;MCP gave agents tools.&lt;/p&gt;

&lt;p&gt;A2A gives agents coworkers.&lt;/p&gt;

&lt;p&gt;That is the simplest way I think about it.&lt;/p&gt;

&lt;p&gt;MCP, or Model Context Protocol, is mostly about connecting an agent to tools, APIs, files, databases, search systems, and external data sources.&lt;/p&gt;

&lt;p&gt;A2A, or Agent2Agent, is about connecting one agent to another agent.&lt;/p&gt;

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

&lt;p&gt;If an agent needs to query a database, call a calendar API, or inspect a repo, MCP is a good fit.&lt;/p&gt;

&lt;p&gt;If an agent needs to delegate work to another autonomous agent with its own capabilities, state, task lifecycle, and output format, A2A is the better mental model.&lt;/p&gt;

&lt;p&gt;A tool usually does one specific thing.&lt;/p&gt;

&lt;p&gt;An agent can own a whole domain of work.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why agents need a collaboration layer
&lt;/h2&gt;

&lt;p&gt;Right now, many agent workflows are still stitched together with prompts.&lt;/p&gt;

&lt;p&gt;Something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;First research the topic.
Then write a draft.
Then review it.
Then create a final version.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That can work for small tasks.&lt;/p&gt;

&lt;p&gt;But it gets messy as soon as the workflow becomes more serious.&lt;/p&gt;

&lt;p&gt;What happens when research takes five minutes?&lt;br&gt;
What happens when the writing agent needs structured data, not a paragraph?&lt;br&gt;
What happens when the reviewer rejects the output?&lt;br&gt;
What happens when the task needs human input?&lt;br&gt;
What happens when the work should continue asynchronously?&lt;/p&gt;

&lt;p&gt;At that point, a prompt chain is not enough.&lt;/p&gt;

&lt;p&gt;You need something closer to a protocol.&lt;/p&gt;

&lt;p&gt;The A2A model introduces concepts like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an &lt;strong&gt;Agent Card&lt;/strong&gt; for discovery&lt;/li&gt;
&lt;li&gt;declared skills and capabilities&lt;/li&gt;
&lt;li&gt;task lifecycle states&lt;/li&gt;
&lt;li&gt;messages between agents&lt;/li&gt;
&lt;li&gt;artifacts as outputs&lt;/li&gt;
&lt;li&gt;streaming updates&lt;/li&gt;
&lt;li&gt;push notifications&lt;/li&gt;
&lt;li&gt;cancellation&lt;/li&gt;
&lt;li&gt;structured data exchange&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Boring protocols are what turn demos into infrastructure.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Agent Card is the underrated part
&lt;/h2&gt;

&lt;p&gt;One of the most useful ideas in A2A is the &lt;strong&gt;Agent Card&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;An Agent Card is basically a description of what an agent is, where it lives, and what it can do.&lt;/p&gt;

&lt;p&gt;It describes identity, capabilities, skills, endpoints, and auth without exposing the agent's internal tools, memory, or private state.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;the agent name&lt;/li&gt;
&lt;li&gt;description&lt;/li&gt;
&lt;li&gt;endpoint URL&lt;/li&gt;
&lt;li&gt;version&lt;/li&gt;
&lt;li&gt;capabilities&lt;/li&gt;
&lt;li&gt;skills&lt;/li&gt;
&lt;li&gt;input modes&lt;/li&gt;
&lt;li&gt;output modes&lt;/li&gt;
&lt;li&gt;authentication requirements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A standard discovery endpoint 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;/.well-known/agent-card.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;may not sound exciting.&lt;/p&gt;

&lt;p&gt;But it solves a real problem.&lt;/p&gt;

&lt;p&gt;If agents are going to collaborate, they need to know who they are talking to.&lt;/p&gt;

&lt;p&gt;A coding agent should be able to discover a code review agent.&lt;br&gt;
A support router should be able to discover a billing agent.&lt;br&gt;
A research agent should be able to discover a writer agent.&lt;/p&gt;

&lt;p&gt;Without a discovery layer, every multi-agent workflow becomes custom glue.&lt;/p&gt;

&lt;p&gt;With one, agents can start to behave more like services.&lt;/p&gt;


&lt;h2&gt;
  
  
  Example: a code pipeline made of agents
&lt;/h2&gt;

&lt;p&gt;Imagine a simple software pipeline.&lt;/p&gt;

&lt;p&gt;You do not want one giant agent doing everything.&lt;/p&gt;

&lt;p&gt;Instead, you split the workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Code writer&lt;/strong&gt; generates the implementation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test writer&lt;/strong&gt; creates tests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code reviewer&lt;/strong&gt; checks both.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orchestrator&lt;/strong&gt; coordinates the flow.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each agent can have a narrow responsibility.&lt;/p&gt;

&lt;p&gt;The code writer does not need to know everything about test strategy.&lt;br&gt;
The test writer does not need to own product requirements.&lt;br&gt;
The reviewer does not need to write the initial implementation.&lt;/p&gt;

&lt;p&gt;This makes the workflow easier to inspect.&lt;/p&gt;

&lt;p&gt;If the tests are weak, improve the test agent.&lt;br&gt;
If the review is shallow, improve the review agent.&lt;br&gt;
If the handoff fails, improve the orchestrator.&lt;/p&gt;

&lt;p&gt;That is much cleaner than debugging one giant prompt with five hidden roles inside it.&lt;/p&gt;


&lt;h2&gt;
  
  
  Example: a customer support router
&lt;/h2&gt;

&lt;p&gt;A2A also makes sense for support.&lt;/p&gt;

&lt;p&gt;A support router agent receives a customer message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I was charged twice and my account still says inactive.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The router should not try to solve everything itself.&lt;/p&gt;

&lt;p&gt;It can delegate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;billing question -&amp;gt; billing agent&lt;/li&gt;
&lt;li&gt;account activation -&amp;gt; technical agent&lt;/li&gt;
&lt;li&gt;refund eligibility -&amp;gt; policy agent&lt;/li&gt;
&lt;li&gt;unclear or sensitive issue -&amp;gt; human handoff&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The router's job is classification, coordination, and response assembly.&lt;/p&gt;

&lt;p&gt;The specialized agents own their own domains.&lt;/p&gt;

&lt;p&gt;This is how real teams work.&lt;/p&gt;

&lt;p&gt;Not everyone does everything.&lt;/p&gt;

&lt;p&gt;The interesting part is making agents follow that same pattern.&lt;/p&gt;




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

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

&lt;p&gt;The &lt;code&gt;a2a-protocol&lt;/code&gt; skill is not just a link to a spec.&lt;/p&gt;

&lt;p&gt;It gives an AI coding agent a practical operating guide for building A2A systems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;when to use A2A&lt;/li&gt;
&lt;li&gt;how to define an Agent Card&lt;/li&gt;
&lt;li&gt;how to build a server&lt;/li&gt;
&lt;li&gt;how to build a client&lt;/li&gt;
&lt;li&gt;how to handle task states&lt;/li&gt;
&lt;li&gt;when to use streaming&lt;/li&gt;
&lt;li&gt;how to orchestrate multiple agents&lt;/li&gt;
&lt;li&gt;how A2A differs from MCP&lt;/li&gt;
&lt;li&gt;what implementation guidelines to follow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That matters because agents often fail not from lack of intelligence, but from lack of workflow structure.&lt;/p&gt;

&lt;p&gt;A model may understand A2A in general.&lt;/p&gt;

&lt;p&gt;But a skill gives it a repeatable path:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;After that, the agent has a focused reference for the task instead of relying on vague memory or generic web knowledge.&lt;/p&gt;

&lt;p&gt;This is the bigger idea behind Terminal Skills:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Agents do not just need more context. They need reusable operational instructions.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  A2A is not a replacement for MCP
&lt;/h2&gt;

&lt;p&gt;It is tempting to turn every new protocol into a winner-takes-all comparison.&lt;/p&gt;

&lt;p&gt;I do not think that is the right framing here.&lt;/p&gt;

&lt;p&gt;A2A and MCP solve different problems.&lt;/p&gt;

&lt;p&gt;A practical way to separate them:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Need&lt;/th&gt;
&lt;th&gt;Better fit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Call a tool or API&lt;/td&gt;
&lt;td&gt;MCP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read from a data source&lt;/td&gt;
&lt;td&gt;MCP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Give an agent access to external systems&lt;/td&gt;
&lt;td&gt;MCP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delegate a task to another agent&lt;/td&gt;
&lt;td&gt;A2A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Discover agent capabilities&lt;/td&gt;
&lt;td&gt;A2A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Coordinate long-running agent work&lt;/td&gt;
&lt;td&gt;A2A&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;MCP is agent-to-tool.&lt;/p&gt;

&lt;p&gt;A2A is agent-to-agent.&lt;/p&gt;

&lt;p&gt;In real systems, you probably want both.&lt;/p&gt;

&lt;p&gt;An agent might use MCP internally to access tools, while exposing an A2A interface so other agents can delegate work to it.&lt;/p&gt;

&lt;p&gt;That combination is where things get interesting.&lt;/p&gt;




&lt;h2&gt;
  
  
  What makes this useful for developers
&lt;/h2&gt;

&lt;p&gt;For developers, the value is not the protocol acronym.&lt;/p&gt;

&lt;p&gt;The value is fewer fragile workflows.&lt;/p&gt;

&lt;p&gt;Instead of hardcoding every handoff, you can start thinking in terms of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;discoverable agents&lt;/li&gt;
&lt;li&gt;declared capabilities&lt;/li&gt;
&lt;li&gt;explicit task states&lt;/li&gt;
&lt;li&gt;structured messages&lt;/li&gt;
&lt;li&gt;cancellable work&lt;/li&gt;
&lt;li&gt;streaming progress&lt;/li&gt;
&lt;li&gt;artifacts as outputs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is closer to software engineering than prompt engineering.&lt;/p&gt;

&lt;p&gt;And honestly, that is the point.&lt;/p&gt;

&lt;p&gt;The next generation of agent systems will not be built from one giant prompt.&lt;/p&gt;

&lt;p&gt;They will look more like networks of specialized workers with clear contracts between them.&lt;/p&gt;

&lt;p&gt;Some of those workers will call tools.&lt;/p&gt;

&lt;p&gt;Some will call other agents.&lt;/p&gt;

&lt;p&gt;The quality of the system will depend less on one model being magical and more on whether the handoffs are well designed.&lt;/p&gt;




&lt;h2&gt;
  
  
  The small shift that matters
&lt;/h2&gt;

&lt;p&gt;The first wave of AI agents was about giving models tools.&lt;/p&gt;

&lt;p&gt;That was a huge step.&lt;/p&gt;

&lt;p&gt;But tools are not the whole story.&lt;/p&gt;

&lt;p&gt;If agents are going to handle real work, they need coordination.&lt;br&gt;
They need delegation.&lt;br&gt;
They need discovery.&lt;br&gt;
They need contracts.&lt;br&gt;
They need ways to say:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I can do this task.
Here is how to call me.
Here is what I return.
Here is how I report progress.
Here is how I fail.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is why A2A is worth watching.&lt;/p&gt;

&lt;p&gt;Not because every project needs a multi-agent architecture today.&lt;/p&gt;

&lt;p&gt;Most do not.&lt;/p&gt;

&lt;p&gt;But because the direction is clear:&lt;/p&gt;

&lt;p&gt;Agents are moving from isolated assistants to interoperable workers.&lt;/p&gt;

&lt;p&gt;MCP gave agents tools.&lt;/p&gt;

&lt;p&gt;A2A gives them coworkers.&lt;/p&gt;

&lt;p&gt;And skills like &lt;code&gt;a2a-protocol&lt;/code&gt; help agents learn how to build that future without starting from a blank prompt.&lt;/p&gt;




&lt;p&gt;If you want to try it, the skill is here:&lt;/p&gt;

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

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

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

&lt;/div&gt;



&lt;p&gt;Then ask your coding agent to build one tiny A2A loop: Agent Card -&amp;gt; server -&amp;gt; client -&amp;gt; delegated task.&lt;/p&gt;

&lt;p&gt;Start small.&lt;/p&gt;

&lt;p&gt;One focused agent.&lt;br&gt;
One clear capability.&lt;br&gt;
One verifiable handoff.&lt;/p&gt;

&lt;p&gt;That is usually where the real workflow begins.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>aiagents</category>
      <category>mcp</category>
      <category>devtools</category>
    </item>
    <item>
      <title>From Blender Demos to Agent Toolchains: Why Terminal Skills Matter</title>
      <dc:creator>Alex Shev</dc:creator>
      <pubDate>Tue, 19 May 2026 04:35:35 +0000</pubDate>
      <link>https://dev.to/alexshev/from-blender-demos-to-agent-toolchains-why-terminal-skills-matter-c0h</link>
      <guid>https://dev.to/alexshev/from-blender-demos-to-agent-toolchains-why-terminal-skills-matter-c0h</guid>
      <description>&lt;p&gt;Most AI + Blender demos still follow the same pattern:&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 model for a prompt.
Generate a scene or script.
Hope the result looks close enough.
Try again when it breaks.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That can be useful for experiments.&lt;/p&gt;

&lt;p&gt;But it is not how real creative work usually gets done.&lt;/p&gt;

&lt;p&gt;Blender is not just an image generator. It is a full production environment with scenes, objects, cameras, lights, materials, modifiers, animation timelines, render settings, exporters, and a Python API.&lt;/p&gt;

&lt;p&gt;So the interesting question is not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can an AI agent describe a Blender workflow?&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;blockquote&gt;
&lt;p&gt;Can an AI agent actually operate Blender as part of a repeatable toolchain?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is where terminal-native skills become interesting.&lt;/p&gt;




&lt;h2&gt;
  
  
  The gap between “knowing Blender” and using Blender
&lt;/h2&gt;

&lt;p&gt;Modern AI models can explain Blender concepts very well.&lt;/p&gt;

&lt;p&gt;They can tell you what a bevel modifier does.&lt;br&gt;
They can describe three-point lighting.&lt;br&gt;
They can write a Python script that creates a simple scene.&lt;br&gt;
They can explain camera focal lengths, materials, render engines, and file exports.&lt;/p&gt;

&lt;p&gt;But knowing the tool is not the same as reliably using the tool.&lt;/p&gt;

&lt;p&gt;If you ask an agent to create a product render in Blender, a lot can go wrong:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the camera may not frame the object&lt;/li&gt;
&lt;li&gt;the lights may be too weak or too harsh&lt;/li&gt;
&lt;li&gt;the material names may be inconsistent&lt;/li&gt;
&lt;li&gt;the render settings may be missing&lt;/li&gt;
&lt;li&gt;the script may assume the wrong scene state&lt;/li&gt;
&lt;li&gt;the output file may never be verified&lt;/li&gt;
&lt;li&gt;the workflow may work once and fail tomorrow&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;A demo can be impressive once.&lt;/p&gt;

&lt;p&gt;A workflow needs to be repeatable.&lt;/p&gt;


&lt;h2&gt;
  
  
  Why Blender is a good test case for AI agents
&lt;/h2&gt;

&lt;p&gt;Blender is creative, but it is also deeply scriptable.&lt;/p&gt;

&lt;p&gt;That makes it a useful benchmark for agent workflows.&lt;/p&gt;

&lt;p&gt;It is not enough for the agent to say something plausible. At the end, there should be an actual artifact:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a &lt;code&gt;.blend&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;a rendered image&lt;/li&gt;
&lt;li&gt;an animation preview&lt;/li&gt;
&lt;li&gt;an exported asset&lt;/li&gt;
&lt;li&gt;a contact sheet&lt;/li&gt;
&lt;li&gt;a set of named cameras&lt;/li&gt;
&lt;li&gt;a reusable scene setup&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Either the output exists or it does not.&lt;/p&gt;

&lt;p&gt;That makes Blender less forgiving than a text-only task, and that is exactly why it is valuable.&lt;/p&gt;

&lt;p&gt;It forces the agent to move from language into execution.&lt;/p&gt;


&lt;h2&gt;
  
  
  The role of Terminal Skills
&lt;/h2&gt;

&lt;p&gt;Terminal Skills is an open-source catalog of skills for AI agents.&lt;/p&gt;

&lt;p&gt;The idea is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Agents do not just need more prompts. They need reusable operational workflows.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A skill can teach an agent how to perform a specific type of work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;when to use the workflow&lt;/li&gt;
&lt;li&gt;what inputs are expected&lt;/li&gt;
&lt;li&gt;which commands or scripts matter&lt;/li&gt;
&lt;li&gt;what conventions to follow&lt;/li&gt;
&lt;li&gt;how to verify the result&lt;/li&gt;
&lt;li&gt;what failure modes to avoid&lt;/li&gt;
&lt;li&gt;what output should be returned&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is different from just giving the agent a tool.&lt;/p&gt;

&lt;p&gt;A tool gives the agent capability.&lt;/p&gt;

&lt;p&gt;A skill gives the agent a path.&lt;/p&gt;

&lt;p&gt;For Blender, that path matters a lot.&lt;/p&gt;


&lt;h2&gt;
  
  
  From GUI work to agent-operable workflows
&lt;/h2&gt;

&lt;p&gt;Blender has a powerful GUI, and artists should absolutely use it.&lt;/p&gt;

&lt;p&gt;But a GUI is not always the best interface for an AI agent.&lt;/p&gt;

&lt;p&gt;Agents work best when they can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;run a command&lt;/li&gt;
&lt;li&gt;inspect files&lt;/li&gt;
&lt;li&gt;read logs&lt;/li&gt;
&lt;li&gt;modify scripts&lt;/li&gt;
&lt;li&gt;verify outputs&lt;/li&gt;
&lt;li&gt;repeat the process&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is why terminal-native workflows are such a natural fit.&lt;/p&gt;

&lt;p&gt;A terminal workflow gives the agent a clean feedback loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;intent → command/script → output → verification → next step
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of guessing inside a visual interface, the agent can perform concrete operations and check whether they worked.&lt;/p&gt;

&lt;p&gt;For example, a Blender skill might help an agent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create a clean scene setup&lt;/li&gt;
&lt;li&gt;generate camera variants&lt;/li&gt;
&lt;li&gt;apply consistent material conventions&lt;/li&gt;
&lt;li&gt;create lighting presets&lt;/li&gt;
&lt;li&gt;render previews&lt;/li&gt;
&lt;li&gt;export assets&lt;/li&gt;
&lt;li&gt;validate that the output file exists&lt;/li&gt;
&lt;li&gt;return a short summary of what changed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The human still controls taste and direction.&lt;/p&gt;

&lt;p&gt;The agent handles the repeatable production layer.&lt;/p&gt;




&lt;h2&gt;
  
  
  What belongs inside a Blender skill
&lt;/h2&gt;

&lt;p&gt;A useful Blender skill is not just a prompt template.&lt;/p&gt;

&lt;p&gt;It should behave more like a small operating manual for the agent.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;what the workflow is for&lt;/li&gt;
&lt;li&gt;what inputs are required&lt;/li&gt;
&lt;li&gt;which files the agent may create or modify&lt;/li&gt;
&lt;li&gt;which commands or scripts should be run&lt;/li&gt;
&lt;li&gt;what naming conventions to follow&lt;/li&gt;
&lt;li&gt;what output artifacts must exist&lt;/li&gt;
&lt;li&gt;how to verify those artifacts&lt;/li&gt;
&lt;li&gt;what common failure modes to check before reporting success&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, instead of giving the agent a vague request 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;Make a Blender product scene.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A skill can define a stronger contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Create or update the scene.
Save the .blend file.
Render a preview.
Confirm the preview file exists.
Return the paths and a short summary of what changed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;It gives the agent a definition of done that is stronger than “the response sounds plausible.”&lt;/p&gt;




&lt;h2&gt;
  
  
  The skill is the interface
&lt;/h2&gt;

&lt;p&gt;A lot of agent tooling conversations focus on connectors.&lt;/p&gt;

&lt;p&gt;Can the agent access this app?&lt;br&gt;
Can it call this API?&lt;br&gt;
Can it run this command?&lt;br&gt;
Can it control this environment?&lt;/p&gt;

&lt;p&gt;Those questions matter.&lt;/p&gt;

&lt;p&gt;But access is not the whole workflow.&lt;/p&gt;

&lt;p&gt;If an agent can run Blender from the terminal, that is useful. But the more important layer is the operating pattern around that access:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what should the agent do first?&lt;/li&gt;
&lt;li&gt;what should it avoid touching?&lt;/li&gt;
&lt;li&gt;how should files be named?&lt;/li&gt;
&lt;li&gt;when should it render a preview?&lt;/li&gt;
&lt;li&gt;what should it check before saying done?&lt;/li&gt;
&lt;li&gt;what should it hand back to the human?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is why I like thinking about skills as interfaces for work.&lt;/p&gt;

&lt;p&gt;They make the task boundary explicit.&lt;/p&gt;

&lt;p&gt;The agent is not just dropped into a powerful tool and told to figure it out.&lt;/p&gt;

&lt;p&gt;It gets a workflow it can execute, inspect, and repeat.&lt;/p&gt;


&lt;h2&gt;
  
  
  A better definition of done
&lt;/h2&gt;

&lt;p&gt;For many AI tasks, “done” is too fuzzy.&lt;/p&gt;

&lt;p&gt;The model stops writing, so the interaction feels complete.&lt;/p&gt;

&lt;p&gt;But production work needs a stronger definition.&lt;/p&gt;

&lt;p&gt;For a Blender workflow, “done” might mean:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;code&gt;.blend&lt;/code&gt; file was saved&lt;/li&gt;
&lt;li&gt;the preview render exists&lt;/li&gt;
&lt;li&gt;the output path was returned&lt;/li&gt;
&lt;li&gt;the scene contains named cameras and lights&lt;/li&gt;
&lt;li&gt;the agent reports what changed&lt;/li&gt;
&lt;li&gt;the human has something concrete to review&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where terminal-native skills become especially useful.&lt;/p&gt;

&lt;p&gt;They can push the agent toward evidence-based completion.&lt;/p&gt;

&lt;p&gt;Not just:&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 a script you could run.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I ran the workflow, created these artifacts, checked these outputs, and here is what needs review.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That difference is small in a demo.&lt;/p&gt;

&lt;p&gt;It is huge in real work.&lt;/p&gt;




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

&lt;p&gt;One-off AI outputs can be impressive, but they are hard to build on.&lt;/p&gt;

&lt;p&gt;If the process is hidden inside a long prompt and a lucky generation, it is difficult to answer basic questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can we run this again next week?&lt;/li&gt;
&lt;li&gt;Can another agent follow the same process?&lt;/li&gt;
&lt;li&gt;Can we change one input and keep the rest consistent?&lt;/li&gt;
&lt;li&gt;Can we debug why the output failed?&lt;/li&gt;
&lt;li&gt;Can we tell which step created which artifact?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Terminal-native workflows are not glamorous, but they help with all of that.&lt;/p&gt;

&lt;p&gt;Commands can be rerun.&lt;br&gt;
Files can be inspected.&lt;br&gt;
Logs can be read.&lt;br&gt;
Outputs can be checked.&lt;br&gt;
Conventions can be documented.&lt;/p&gt;

&lt;p&gt;A skill wraps those pieces into something the agent can reuse.&lt;/p&gt;

&lt;p&gt;That is the real value.&lt;/p&gt;

&lt;p&gt;Not magic.&lt;/p&gt;

&lt;p&gt;Repeatability.&lt;/p&gt;


&lt;h2&gt;
  
  
  Why this matters beyond Blender
&lt;/h2&gt;

&lt;p&gt;Blender is just one example.&lt;/p&gt;

&lt;p&gt;The same pattern applies to many agent workflows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;video processing&lt;/li&gt;
&lt;li&gt;data cleanup&lt;/li&gt;
&lt;li&gt;documentation updates&lt;/li&gt;
&lt;li&gt;screenshot generation&lt;/li&gt;
&lt;li&gt;test automation&lt;/li&gt;
&lt;li&gt;asset exports&lt;/li&gt;
&lt;li&gt;report generation&lt;/li&gt;
&lt;li&gt;deployment checks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In each case, the problem is not only whether the model understands the task.&lt;/p&gt;

&lt;p&gt;The problem is whether the agent has a reliable way to perform the task.&lt;/p&gt;

&lt;p&gt;That usually requires more than a prompt.&lt;/p&gt;

&lt;p&gt;It requires operational knowledge:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;steps&lt;/li&gt;
&lt;li&gt;defaults&lt;/li&gt;
&lt;li&gt;constraints&lt;/li&gt;
&lt;li&gt;checks&lt;/li&gt;
&lt;li&gt;outputs&lt;/li&gt;
&lt;li&gt;failure handling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is what skills are good at packaging.&lt;/p&gt;


&lt;h2&gt;
  
  
  Skills make agent work more auditable
&lt;/h2&gt;

&lt;p&gt;One underrated benefit of terminal-native skills is auditability.&lt;/p&gt;

&lt;p&gt;When an agent uses a repeatable workflow, it can leave evidence:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;which files were created&lt;/li&gt;
&lt;li&gt;which commands were run&lt;/li&gt;
&lt;li&gt;which checks passed&lt;/li&gt;
&lt;li&gt;where the output was saved&lt;/li&gt;
&lt;li&gt;what still needs human review&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That makes agent work easier to trust.&lt;/p&gt;

&lt;p&gt;Not because the agent becomes magically perfect.&lt;/p&gt;

&lt;p&gt;Because the workflow becomes visible.&lt;/p&gt;

&lt;p&gt;For creative work, that matters.&lt;/p&gt;

&lt;p&gt;A human should not have to guess whether the agent actually rendered the scene, exported the asset, or just stopped after writing a script.&lt;/p&gt;

&lt;p&gt;The output should be inspectable.&lt;/p&gt;


&lt;h2&gt;
  
  
  The practical takeaway
&lt;/h2&gt;

&lt;p&gt;If you are building with AI agents, do not only 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 tools can my agent access?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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 repeatable workflows can my agent follow?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Blender makes this obvious because the final result is concrete.&lt;/p&gt;

&lt;p&gt;A good agent workflow should not end with “here is some code you could run.”&lt;/p&gt;

&lt;p&gt;It should end with an artifact, a check, and a clear next step.&lt;/p&gt;

&lt;p&gt;That is the shift Terminal Skills is designed around:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;less one-off prompting&lt;/li&gt;
&lt;li&gt;more reusable workflows&lt;/li&gt;
&lt;li&gt;less hidden improvisation&lt;/li&gt;
&lt;li&gt;more executable, verifiable work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Agents do not need to become artists.&lt;/p&gt;

&lt;p&gt;But they can become much better production assistants.&lt;/p&gt;

&lt;p&gt;And for tools like Blender, that is already a very useful place to start.&lt;/p&gt;




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

&lt;p&gt;Blender is useful here because it makes the gap visible.&lt;/p&gt;

&lt;p&gt;If the render file does not exist, the workflow failed.&lt;br&gt;
If the camera misses the object, the workflow failed.&lt;br&gt;
If the agent cannot explain what changed, the workflow is hard to trust.&lt;/p&gt;

&lt;p&gt;That same lesson applies to other agent work too.&lt;/p&gt;

&lt;p&gt;Terminal Skills is about turning repeatable work into reusable operational knowledge: not just what the agent should know, but how it should act, check itself, and report the result.&lt;/p&gt;




&lt;p&gt;If you want to explore the catalog, Terminal Skills is open-source and available at &lt;a href="https://terminalskills.io/" rel="noopener noreferrer"&gt;terminalskills.io&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;AI assistance was used while drafting this article. The final structure, edits, and publishing decisions are human-reviewed.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>automation</category>
      <category>cli</category>
    </item>
    <item>
      <title>How AI Agents Can Use Blender Like a Real Tool, Not Just Generate Prompts</title>
      <dc:creator>Alex Shev</dc:creator>
      <pubDate>Sat, 16 May 2026 13:44:21 +0000</pubDate>
      <link>https://dev.to/alexshev/how-ai-agents-can-use-blender-like-a-real-tool-not-just-generate-prompts-if8</link>
      <guid>https://dev.to/alexshev/how-ai-agents-can-use-blender-like-a-real-tool-not-just-generate-prompts-if8</guid>
      <description>&lt;p&gt;Most AI demos around 3D creation still have the same shape:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Write a prompt.
Hope the model understands the scene.
Regenerate until it looks close enough.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;That is trial and error with prettier tooling.&lt;/p&gt;

&lt;p&gt;That can be useful for concept art.&lt;/p&gt;

&lt;p&gt;But Blender is not just a visual output machine.&lt;/p&gt;

&lt;p&gt;Blender is a real production tool. It has scenes, objects, modifiers, materials, cameras, lighting, animation timelines, render settings, file exports, and a Python API that can control a large part of it.&lt;/p&gt;

&lt;p&gt;So when an AI agent works with Blender, the goal should not be “make a nice image from a prompt.”&lt;/p&gt;

&lt;p&gt;The goal should be:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Let the agent perform repeatable 3D work inside Blender.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;Because prompts are vague.&lt;/p&gt;

&lt;p&gt;Tools are executable.&lt;/p&gt;




&lt;h2&gt;
  
  
  The problem: agents “know” Blender, but they do not always operate Blender well
&lt;/h2&gt;

&lt;p&gt;A capable AI model can explain Blender concepts all day:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what a bevel modifier does&lt;/li&gt;
&lt;li&gt;how materials work&lt;/li&gt;
&lt;li&gt;how to set up a camera&lt;/li&gt;
&lt;li&gt;how to create a simple animation&lt;/li&gt;
&lt;li&gt;how to use Python inside Blender&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;But knowledge is not the same as a reliable workflow.&lt;/p&gt;

&lt;p&gt;If you ask an agent:&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 cinematic product render in Blender.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;it may generate a decent Python script.&lt;/p&gt;

&lt;p&gt;Or it may forget a render setting.&lt;/p&gt;

&lt;p&gt;Or create a camera that points in the wrong direction.&lt;/p&gt;

&lt;p&gt;Or use objects with inconsistent scale.&lt;/p&gt;

&lt;p&gt;Or produce something that only works in one local Blender version.&lt;/p&gt;

&lt;p&gt;Or fail silently because the script assumes a scene state that does not exist.&lt;/p&gt;

&lt;p&gt;This is the gap between “the model knows Blender” and “the agent can actually use Blender as a tool.”&lt;/p&gt;

&lt;p&gt;For real work, that gap gets expensive fast.&lt;/p&gt;




&lt;h2&gt;
  
  
  A better mental model: Blender skills as reusable workflows
&lt;/h2&gt;

&lt;p&gt;Instead of asking the agent to invent a Blender workflow from scratch every time, give it a reusable skill.&lt;/p&gt;

&lt;p&gt;A skill is not just a longer prompt.&lt;/p&gt;

&lt;p&gt;A good skill packages the operational knowledge around a task:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what the agent should do&lt;/li&gt;
&lt;li&gt;what files or inputs it should expect&lt;/li&gt;
&lt;li&gt;which commands or scripts to run&lt;/li&gt;
&lt;li&gt;what quality checks matter&lt;/li&gt;
&lt;li&gt;what output should be produced&lt;/li&gt;
&lt;li&gt;what common failure modes to avoid&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For Blender, that might mean a skill for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;creating a clean scene setup&lt;/li&gt;
&lt;li&gt;adding materials consistently&lt;/li&gt;
&lt;li&gt;generating camera views&lt;/li&gt;
&lt;li&gt;setting lighting presets&lt;/li&gt;
&lt;li&gt;rendering thumbnails&lt;/li&gt;
&lt;li&gt;exporting assets&lt;/li&gt;
&lt;li&gt;automating turntable animations&lt;/li&gt;
&lt;li&gt;building simple procedural objects&lt;/li&gt;
&lt;li&gt;validating that the render actually exists&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The agent still reasons.&lt;/p&gt;

&lt;p&gt;But it does not need to rediscover the workflow every time.&lt;/p&gt;

&lt;p&gt;It can follow a known path.&lt;/p&gt;




&lt;h2&gt;
  
  
  Example: scene setup should be boring
&lt;/h2&gt;

&lt;p&gt;Scene setup is one of those tasks that sounds simple until you repeat it often.&lt;/p&gt;

&lt;p&gt;You may want the same basics every time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;clear the default cube&lt;/li&gt;
&lt;li&gt;set units&lt;/li&gt;
&lt;li&gt;create a camera&lt;/li&gt;
&lt;li&gt;add a key light and fill light&lt;/li&gt;
&lt;li&gt;set world color&lt;/li&gt;
&lt;li&gt;configure resolution&lt;/li&gt;
&lt;li&gt;set render engine&lt;/li&gt;
&lt;li&gt;save the file&lt;/li&gt;
&lt;li&gt;optionally render a preview&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is exactly the kind of thing that should not depend on a fresh model improvisation.&lt;/p&gt;

&lt;p&gt;A Blender skill can turn that into a repeatable operation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Use the Blender scene setup skill.
Create a 16:9 product render scene.
Use a dark studio background.
Add camera, key light, fill light, and ground plane.
Return the .blend file and preview render.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the agent has a workflow boundary.&lt;/p&gt;

&lt;p&gt;It knows the task is not “be creative forever.”&lt;/p&gt;

&lt;p&gt;It knows the expected output.&lt;/p&gt;

&lt;p&gt;It knows what success looks like.&lt;/p&gt;

&lt;p&gt;That is a much better interface than a vague creative prompt.&lt;/p&gt;




&lt;h2&gt;
  
  
  Example: materials are easier when the agent has conventions
&lt;/h2&gt;

&lt;p&gt;Materials are another good case.&lt;/p&gt;

&lt;p&gt;If you ask an agent to “make it look premium,” it can go in many directions.&lt;/p&gt;

&lt;p&gt;Sometimes that is fine.&lt;/p&gt;

&lt;p&gt;But production work usually needs conventions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use named materials&lt;/li&gt;
&lt;li&gt;avoid random node spaghetti&lt;/li&gt;
&lt;li&gt;keep roughness/metallic values sane&lt;/li&gt;
&lt;li&gt;separate glass, metal, plastic, rubber, and emission materials&lt;/li&gt;
&lt;li&gt;make assets readable under different lighting&lt;/li&gt;
&lt;li&gt;document what was created&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A skill can encode those conventions.&lt;/p&gt;

&lt;p&gt;Then the agent can apply them consistently instead of guessing from scratch.&lt;/p&gt;

&lt;p&gt;This is especially useful when multiple agents or multiple projects touch the same assets.&lt;/p&gt;

&lt;p&gt;The output becomes easier to review.&lt;/p&gt;

&lt;p&gt;And easier to fix.&lt;/p&gt;




&lt;h2&gt;
  
  
  Example: camera automation is not just aesthetics
&lt;/h2&gt;

&lt;p&gt;Camera placement is one of the quickest ways to make a 3D result look broken.&lt;/p&gt;

&lt;p&gt;The scene can be good, but if the camera is inside an object, too far away, pointed at the wrong target, or using the wrong focal length, the render fails as a deliverable.&lt;/p&gt;

&lt;p&gt;A reusable camera skill can define practical defaults:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;frame the selected object&lt;/li&gt;
&lt;li&gt;use a target empty&lt;/li&gt;
&lt;li&gt;set focal length by shot type&lt;/li&gt;
&lt;li&gt;create front, side, top, and hero views&lt;/li&gt;
&lt;li&gt;verify the object is visible&lt;/li&gt;
&lt;li&gt;save camera names clearly&lt;/li&gt;
&lt;li&gt;render contact sheets for review&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That gives the agent a real operation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Generate 4 review cameras for this model and render a contact sheet.
&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;Make the camera look good.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second version is subjective.&lt;/p&gt;

&lt;p&gt;The first version is work.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why terminal-based skills fit Blender well
&lt;/h2&gt;

&lt;p&gt;Blender is not only a GUI app.&lt;/p&gt;

&lt;p&gt;It can run headless.&lt;/p&gt;

&lt;p&gt;It can execute Python scripts.&lt;/p&gt;

&lt;p&gt;It can render from the command line.&lt;/p&gt;

&lt;p&gt;That makes it a strong fit for agent workflows.&lt;/p&gt;

&lt;p&gt;An agent can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;prepare a script&lt;/li&gt;
&lt;li&gt;run Blender in background mode&lt;/li&gt;
&lt;li&gt;generate or modify a scene&lt;/li&gt;
&lt;li&gt;render a preview&lt;/li&gt;
&lt;li&gt;inspect whether output files exist&lt;/li&gt;
&lt;li&gt;return the result for review&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A small workflow might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;blender &lt;span class="nt"&gt;-b&lt;/span&gt; template.blend &lt;span class="nt"&gt;--python&lt;/span&gt; scripts/setup_scene.py &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt; renders/preview.png
&lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; renders/preview.png
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent runs Blender headless, lets the script create or update the scene, checks that the preview render exists, and returns the image for review.&lt;/p&gt;

&lt;p&gt;That is a much stronger loop than “generate something and hope it worked.”&lt;/p&gt;

&lt;p&gt;This is exactly where terminal skills become useful.&lt;/p&gt;

&lt;p&gt;They give the agent a practical bridge between natural language and repeatable execution.&lt;/p&gt;

&lt;p&gt;Instead of treating Blender as a mystical creative box, the agent treats it like a real toolchain.&lt;/p&gt;

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




&lt;h2&gt;
  
  
  The key is not replacing artists
&lt;/h2&gt;

&lt;p&gt;This is not about replacing 3D artists.&lt;/p&gt;

&lt;p&gt;It is about removing repetitive setup work and making agent output easier to trust.&lt;/p&gt;

&lt;p&gt;Artists still make judgment calls:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;composition&lt;/li&gt;
&lt;li&gt;style&lt;/li&gt;
&lt;li&gt;taste&lt;/li&gt;
&lt;li&gt;realism&lt;/li&gt;
&lt;li&gt;brand fit&lt;/li&gt;
&lt;li&gt;final polish&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But agents can help with the mechanical layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;generate scene variants&lt;/li&gt;
&lt;li&gt;batch render previews&lt;/li&gt;
&lt;li&gt;create consistent lighting setups&lt;/li&gt;
&lt;li&gt;prepare template files&lt;/li&gt;
&lt;li&gt;automate exports&lt;/li&gt;
&lt;li&gt;produce review contact sheets&lt;/li&gt;
&lt;li&gt;validate file outputs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is useful because it gives humans more time for the parts where taste matters.&lt;/p&gt;

&lt;p&gt;The agent handles the repeatable work.&lt;/p&gt;

&lt;p&gt;The human reviews, directs, and improves.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prompting is still part of the workflow — just not the whole workflow
&lt;/h2&gt;

&lt;p&gt;Prompts are not bad.&lt;/p&gt;

&lt;p&gt;They are still how we describe intent.&lt;/p&gt;

&lt;p&gt;The issue is pretending the prompt is the entire production system.&lt;/p&gt;

&lt;p&gt;For Blender work, the better structure is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Intent → Skill → Execution → Output → Review
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The prompt describes the goal.&lt;/p&gt;

&lt;p&gt;The skill defines the workflow.&lt;/p&gt;

&lt;p&gt;The tool executes the work.&lt;/p&gt;

&lt;p&gt;The output proves what happened.&lt;/p&gt;

&lt;p&gt;The review decides what comes next.&lt;/p&gt;

&lt;p&gt;That loop is much healthier than endless prompt regeneration.&lt;/p&gt;




&lt;h2&gt;
  
  
  What this unlocks
&lt;/h2&gt;

&lt;p&gt;When agents use Blender through reusable skills, a lot of workflows become more realistic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;product mockups&lt;/li&gt;
&lt;li&gt;simple 3D thumbnails&lt;/li&gt;
&lt;li&gt;procedural scenes&lt;/li&gt;
&lt;li&gt;animation previews&lt;/li&gt;
&lt;li&gt;asset cleanup&lt;/li&gt;
&lt;li&gt;batch rendering&lt;/li&gt;
&lt;li&gt;format conversion&lt;/li&gt;
&lt;li&gt;lighting tests&lt;/li&gt;
&lt;li&gt;camera studies&lt;/li&gt;
&lt;li&gt;social media visuals&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this requires the agent to be magically perfect.&lt;/p&gt;

&lt;p&gt;It requires the agent to have a reliable way to act.&lt;/p&gt;

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

&lt;p&gt;The future of AI agents in creative tools will not just be bigger models writing prettier prompts.&lt;/p&gt;

&lt;p&gt;It will be agents using real tools through small, reliable workflows.&lt;/p&gt;

&lt;p&gt;Blender is one of the best places to see that shift.&lt;/p&gt;




&lt;p&gt;If you are building agent workflows around tools like Blender, the 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;Can the model describe the task?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;Can the agent perform the task, check the output, and repeat it tomorrow?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is where skills matter.&lt;/p&gt;

&lt;p&gt;And that is why AI agents should use Blender like a real tool — not just another prompt box.&lt;/p&gt;




&lt;p&gt;I am building and collecting practical AI agent skills at &lt;a href="https://terminalskills.io" rel="noopener noreferrer"&gt;Terminal Skills&lt;/a&gt;, including workflows for tools like Blender, FFmpeg, and other command-line-first creative/dev tools.&lt;/p&gt;

&lt;p&gt;If you are experimenting with agents that need to do real work instead of just generate text, the useful shift is to think in skills, not only prompts.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;AI assistance was used while drafting this article. The final structure, edits, and publishing decisions are human-reviewed.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>automation</category>
      <category>blender</category>
      <category>cli</category>
    </item>
    <item>
      <title>Your AI Agent Does Not Need More Context. It Needs a Smaller Workflow.</title>
      <dc:creator>Alex Shev</dc:creator>
      <pubDate>Wed, 13 May 2026 22:38:18 +0000</pubDate>
      <link>https://dev.to/alexshev/your-ai-agent-does-not-need-more-context-it-needs-a-smaller-workflow-41p3</link>
      <guid>https://dev.to/alexshev/your-ai-agent-does-not-need-more-context-it-needs-a-smaller-workflow-41p3</guid>
      <description>&lt;p&gt;A lot of AI agent workflows are becoming expensive for a very boring reason:&lt;/p&gt;

&lt;p&gt;We keep giving the agent too much context and not enough direction.&lt;/p&gt;

&lt;p&gt;The usual pattern looks 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;Here is my whole repo.
Here are 12 tools.
Here are 9 docs.
Here is the bug.
Please figure it out.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;But it is also how you end up with huge token usage, messy tool calls, slow runs, and an agent that spends half the session rediscovering what a human already knows.&lt;/p&gt;

&lt;p&gt;More context feels safer.&lt;/p&gt;

&lt;p&gt;In practice, it often makes the workflow worse.&lt;/p&gt;




&lt;h2&gt;
  
  
  The problem is not context. The problem is unfiltered context.
&lt;/h2&gt;

&lt;p&gt;AI agents do need context.&lt;/p&gt;

&lt;p&gt;They need the right files, the right constraints, the right examples, and the right definition of done.&lt;/p&gt;

&lt;p&gt;What they do not need is every possible thing that might be relevant.&lt;/p&gt;

&lt;p&gt;That is where many workflows go wrong.&lt;/p&gt;

&lt;p&gt;A small task becomes a giant investigation because the agent has no boundary.&lt;/p&gt;

&lt;p&gt;For example, imagine asking an agent to update a pricing component.&lt;/p&gt;

&lt;p&gt;Bad version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Read the app and update the pricing page.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Update the pricing card component.
Only inspect files under components/pricing and app/pricing.
Do not change billing logic.
Run the component test and TypeScript check.
Return a short summary plus changed files.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second prompt is not just shorter.&lt;/p&gt;

&lt;p&gt;It is a smaller workflow.&lt;/p&gt;

&lt;p&gt;That is the part that matters.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tools make this easier and harder
&lt;/h2&gt;

&lt;p&gt;MCP and other tool protocols are useful because they give agents cleaner access to external systems.&lt;/p&gt;

&lt;p&gt;That is a real improvement.&lt;/p&gt;

&lt;p&gt;But tool access also creates a new problem:&lt;/p&gt;

&lt;p&gt;The agent can now search more, read more, call more APIs, and collect more context than it actually needs.&lt;/p&gt;

&lt;p&gt;A connected agent is powerful.&lt;/p&gt;

&lt;p&gt;A connected agent with no workflow boundary is expensive.&lt;/p&gt;

&lt;p&gt;This is why I think a lot of teams are asking the wrong question.&lt;/p&gt;

&lt;p&gt;The 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;What tools can my agent access?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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 is the smallest reliable workflow this task needs?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That one question changes how you design the agent.&lt;/p&gt;




&lt;h2&gt;
  
  
  A workflow beats a giant prompt
&lt;/h2&gt;

&lt;p&gt;When I say “workflow,” I mean a repeatable operating pattern:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;when to use it&lt;/li&gt;
&lt;li&gt;which files or tools are in scope&lt;/li&gt;
&lt;li&gt;which files or tools are out of scope&lt;/li&gt;
&lt;li&gt;what steps to follow&lt;/li&gt;
&lt;li&gt;what checks to run&lt;/li&gt;
&lt;li&gt;what output format to return&lt;/li&gt;
&lt;li&gt;what should trigger a human handoff&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is different from a one-off prompt.&lt;/p&gt;

&lt;p&gt;A prompt is a request.&lt;/p&gt;

&lt;p&gt;A workflow is a habit.&lt;/p&gt;

&lt;p&gt;And agents need good habits more than they need another 2,000 words of instructions.&lt;/p&gt;




&lt;h2&gt;
  
  
  Example: debugging without reading the universe
&lt;/h2&gt;

&lt;p&gt;Here is a simple debugging workflow I use mentally all the time.&lt;/p&gt;

&lt;p&gt;Instead of telling the agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Debug this issue.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I want the agent to follow a narrow loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Reproduce the error.
2. Identify the smallest failing command or test.
3. Inspect only the files directly involved.
4. Make one focused change.
5. Re-run the failing check.
6. Stop if the fix requires product judgment.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That workflow does two useful things.&lt;/p&gt;

&lt;p&gt;First, it keeps the agent from wandering through unrelated code.&lt;/p&gt;

&lt;p&gt;Second, it creates a clear stopping point.&lt;/p&gt;

&lt;p&gt;A lot of agent waste happens because there is no stopping point.&lt;/p&gt;

&lt;p&gt;The agent keeps searching, summarizing, and patching because “done” was never defined.&lt;/p&gt;




&lt;h2&gt;
  
  
  Example: code review with a smaller surface area
&lt;/h2&gt;

&lt;p&gt;The same idea applies to code review.&lt;/p&gt;

&lt;p&gt;A vague agent review 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;Review this PR.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That can produce a long list of generic comments.&lt;/p&gt;

&lt;p&gt;A smaller workflow is better:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Review only for:
- data loss risks
- auth or permission mistakes
- broken edge cases
- missing tests for changed behavior

Ignore style unless it affects correctness.
Return only high-confidence findings.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This turns the agent from a noisy reviewer into a useful filter.&lt;/p&gt;

&lt;p&gt;It also saves attention.&lt;/p&gt;

&lt;p&gt;The goal is not to make the agent say more.&lt;/p&gt;

&lt;p&gt;The goal is to make the agent say fewer, better things.&lt;/p&gt;




&lt;h2&gt;
  
  
  This is where skills help
&lt;/h2&gt;

&lt;p&gt;This is why I like packaging repeatable workflows as skills.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;For this kind of task, use this workflow.
Use these tools.
Avoid these traps.
Verify with these checks.
Return this output.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is much more useful than repeatedly writing giant prompts.&lt;/p&gt;

&lt;p&gt;For example, a media-processing skill could teach the agent the standard FFmpeg workflow.&lt;/p&gt;

&lt;p&gt;A deployment skill could teach it the exact deploy and verification steps.&lt;/p&gt;

&lt;p&gt;A code-review skill could teach it what kinds of issues matter and what kinds of comments to ignore.&lt;/p&gt;

&lt;p&gt;A security skill could tell it when to stop and ask for human approval.&lt;/p&gt;

&lt;p&gt;The skill is not magic.&lt;/p&gt;

&lt;p&gt;It is just reusable judgment.&lt;/p&gt;

&lt;p&gt;And reusable judgment is exactly what most agent setups are missing.&lt;/p&gt;




&lt;h2&gt;
  
  
  The smallest workflow test
&lt;/h2&gt;

&lt;p&gt;Before giving an agent a task, I like to 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 is the smallest workflow that can finish this safely?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I reduce the task until the answer is clear.&lt;/p&gt;

&lt;p&gt;That usually means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fewer files&lt;/li&gt;
&lt;li&gt;fewer tools&lt;/li&gt;
&lt;li&gt;fewer open-ended instructions&lt;/li&gt;
&lt;li&gt;more explicit checks&lt;/li&gt;
&lt;li&gt;a clearer definition of done&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This sounds less impressive than “agent with full repo access and every tool connected.”&lt;/p&gt;

&lt;p&gt;But it works better.&lt;/p&gt;

&lt;p&gt;Small workflows are easier to test.&lt;/p&gt;

&lt;p&gt;Small workflows are easier to repeat.&lt;/p&gt;

&lt;p&gt;Small workflows are easier to trust.&lt;/p&gt;




&lt;h2&gt;
  
  
  My rule of thumb
&lt;/h2&gt;

&lt;p&gt;If an agent keeps burning tokens, I do not immediately add a better model.&lt;/p&gt;

&lt;p&gt;I ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is the task too broad?&lt;/li&gt;
&lt;li&gt;Did I give it too many tools?&lt;/li&gt;
&lt;li&gt;Did I define done?&lt;/li&gt;
&lt;li&gt;Did I tell it what not to inspect?&lt;/li&gt;
&lt;li&gt;Can this become a reusable skill?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most of the time, the fix is not more intelligence.&lt;/p&gt;

&lt;p&gt;It is less ambiguity.&lt;/p&gt;




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

&lt;p&gt;AI agents are getting better fast.&lt;/p&gt;

&lt;p&gt;But better models will not remove the need for workflow design.&lt;/p&gt;

&lt;p&gt;If anything, stronger agents make workflow design more important because they can do more damage, spend more tokens, and move faster in the wrong direction.&lt;/p&gt;

&lt;p&gt;The next layer of useful agent work is not just bigger context windows.&lt;/p&gt;

&lt;p&gt;It is smaller, clearer, reusable workflows.&lt;/p&gt;

&lt;p&gt;That is what I am collecting at Terminal Skills: practical examples of skills that give agents narrower, repeatable ways to do real work.&lt;/p&gt;

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

&lt;p&gt;More context is not always the answer.&lt;/p&gt;

&lt;p&gt;Sometimes the best thing you can give an AI agent is a smaller job.&lt;/p&gt;

&lt;p&gt;AI-assisted. Human reviewed.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>devtools</category>
      <category>programming</category>
    </item>
    <item>
      <title>AI Receptionist Cost in 2026: How to Calculate ROI for Small Business Automation</title>
      <dc:creator>Alex Shev</dc:creator>
      <pubDate>Thu, 07 May 2026 23:43:57 +0000</pubDate>
      <link>https://dev.to/alexshev/ai-receptionist-cost-in-2026-how-to-calculate-roi-for-small-business-automation-8cb</link>
      <guid>https://dev.to/alexshev/ai-receptionist-cost-in-2026-how-to-calculate-roi-for-small-business-automation-8cb</guid>
      <description>&lt;p&gt;This is a practical breakdown for builders, consultants, and operators thinking about AI phone automation for small businesses.&lt;/p&gt;

&lt;p&gt;The goal is not to hype “AI receptionists,” but to show what actually drives cost: call volume, integrations, booking workflows, follow-up, and missed-call recovery.&lt;/p&gt;

&lt;p&gt;Small-business owners are not asking whether AI can answer the phone anymore. They are asking what an AI receptionist costs, what is included, and whether it pays for itself faster than hiring another front-desk person.&lt;/p&gt;

&lt;p&gt;The honest answer is that AI receptionist cost depends on what you expect the system to do. A basic voice bot that takes messages is one category. A real AI employee that answers calls, texts missed callers, books appointments, updates your CRM, and follows up with leads is a different investment.&lt;/p&gt;

&lt;p&gt;This guide breaks down AI receptionist pricing in practical terms so you can compare monthly cost against recovered calls, booked jobs, after-hours leads, and staff time saved.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Affects AI Receptionist Cost?
&lt;/h2&gt;

&lt;p&gt;Most pricing differences come from capability, not from the word “AI.” A cheap system may answer calls but fail when the caller asks a real question. A stronger system understands your business rules and turns conversations into outcomes.&lt;/p&gt;

&lt;p&gt;The main drivers are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;call volume and whether pricing is per minute or flat monthly&lt;/li&gt;
&lt;li&gt;voice quality and how natural the conversation feels&lt;/li&gt;
&lt;li&gt;whether it can text, email, and follow up after the call&lt;/li&gt;
&lt;li&gt;calendar, CRM, payment, and dispatch integrations&lt;/li&gt;
&lt;li&gt;setup work: scripts, FAQs, service areas, offers, and escalation rules&lt;/li&gt;
&lt;li&gt;reporting on missed calls, booked appointments, and revenue impact&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Basic AI Answering vs. Full AI Receptionist
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Basic call handling
&lt;/h3&gt;

&lt;p&gt;Entry-level tools are useful if you only need a greeting, simple routing, or voicemail replacement. They are usually cheaper, but they often stop at message-taking. For businesses that depend on booked appointments, that is not enough.&lt;/p&gt;

&lt;h3&gt;
  
  
  Full AI receptionist
&lt;/h3&gt;

&lt;p&gt;A full AI receptionist behaves more like a trained front-desk employee. It answers common questions, qualifies the lead, checks availability, books the next step, sends confirmations, and escalates edge cases. That is where ROI usually appears.&lt;/p&gt;

&lt;p&gt;If an AI receptionist only saves labor, the math is decent. If it captures leads that were previously lost, the math gets much better.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Calculate ROI
&lt;/h2&gt;

&lt;p&gt;Use a simple model before buying anything. Start with the calls you already receive, not fantasy traffic.&lt;/p&gt;

&lt;p&gt;Ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How many calls do you miss each week?&lt;/li&gt;
&lt;li&gt;How many after-hours calls go to voicemail?&lt;/li&gt;
&lt;li&gt;What percentage of callers become booked appointments?&lt;/li&gt;
&lt;li&gt;What is one booked job or consultation worth?&lt;/li&gt;
&lt;li&gt;How much staff time goes into answering repeat questions?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If AI recovers just 5 to 10 extra leads per month and each booked customer is worth hundreds or thousands of dollars, the system can pay for itself quickly.&lt;/p&gt;

&lt;p&gt;This is why phone-heavy businesses often see ROI faster than companies with low call volume.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where Small Businesses Usually Overpay
&lt;/h2&gt;

&lt;p&gt;Some businesses overpay for software that looks advanced but does not connect to operations. Others underpay for a cheap bot, then still need staff to clean up every conversation.&lt;/p&gt;

&lt;p&gt;The goal is not the lowest monthly invoice. The goal is the lowest cost per qualified appointment.&lt;/p&gt;

&lt;p&gt;Before choosing a tool, ask whether it can handle your actual calls:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;pricing questions&lt;/li&gt;
&lt;li&gt;service-area checks&lt;/li&gt;
&lt;li&gt;emergency routing&lt;/li&gt;
&lt;li&gt;appointment changes&lt;/li&gt;
&lt;li&gt;lead qualification&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If it cannot, the “savings” may disappear into manual cleanup.&lt;/p&gt;




&lt;h2&gt;
  
  
  Best Fit Businesses
&lt;/h2&gt;

&lt;p&gt;AI receptionist systems tend to fit best when the phone is directly connected to revenue or operations.&lt;/p&gt;

&lt;p&gt;Good examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;home service companies with technicians in the field&lt;/li&gt;
&lt;li&gt;med spas, clinics, salons, and appointment-based local businesses&lt;/li&gt;
&lt;li&gt;professional services that miss calls during client work&lt;/li&gt;
&lt;li&gt;restaurants and hospitality businesses with repetitive phone questions&lt;/li&gt;
&lt;li&gt;any company paying for Google Ads, Local Services Ads, or social traffic&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How much does an AI receptionist cost for a small business?
&lt;/h3&gt;

&lt;p&gt;Pricing varies widely. Simple AI answering tools may be relatively low-cost, while full-service implementations with scheduling, CRM integration, follow-up, and reporting cost more.&lt;/p&gt;

&lt;p&gt;Many full-service AI receptionist implementations can land around $1,000–3,000 per month, depending on scope.&lt;/p&gt;

&lt;p&gt;The real cost depends on call volume, voice quality, scheduling, CRM integrations, and whether the system can book appointments instead of only taking messages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is an AI receptionist cheaper than hiring a human receptionist?
&lt;/h3&gt;

&lt;p&gt;Usually yes, especially when the goal is 24/7 coverage. A full-time receptionist includes salary, payroll taxes, benefits, training, management, and coverage gaps.&lt;/p&gt;

&lt;p&gt;An AI receptionist can provide round-the-clock call coverage and lead capture for a predictable monthly cost.&lt;/p&gt;

&lt;h3&gt;
  
  
  What gives an AI receptionist the fastest ROI?
&lt;/h3&gt;

&lt;p&gt;The fastest ROI usually comes from recovering missed calls, booking after-hours leads, reducing voicemail leakage, and following up instantly with people who would otherwise call a competitor.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;An AI receptionist should be judged by booked outcomes, not novelty.&lt;/p&gt;

&lt;p&gt;If it answers calls, responds after hours, follows up instantly, and gets more prospects onto the calendar, it is not just a phone tool. It is a revenue-protection layer.&lt;/p&gt;

&lt;p&gt;Originally published on AIEmployees:&lt;br&gt;
&lt;a href="https://aiemployees.us/blog/ai-receptionist-cost-small-business-2026" rel="noopener noreferrer"&gt;https://aiemployees.us/blog/ai-receptionist-cost-small-business-2026&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>automation</category>
      <category>productivity</category>
      <category>business</category>
    </item>
    <item>
      <title>How I Built a CLI Skill to Batch-Process YouTube Shorts</title>
      <dc:creator>Alex Shev</dc:creator>
      <pubDate>Thu, 07 May 2026 23:38:39 +0000</pubDate>
      <link>https://dev.to/alexshev/how-i-built-a-cli-skill-to-batch-process-youtube-shorts-476k</link>
      <guid>https://dev.to/alexshev/how-i-built-a-cli-skill-to-batch-process-youtube-shorts-476k</guid>
      <description>&lt;p&gt;Last month, I had to process 16 YouTube Shorts.&lt;/p&gt;

&lt;p&gt;Trim intros. Normalize audio. Add watermarks. Export multiple formats. Generate thumbnails.&lt;/p&gt;

&lt;p&gt;Doing that manually in Premiere would have taken me most of an afternoon.&lt;/p&gt;

&lt;p&gt;So I built a CLI skill instead.&lt;/p&gt;

&lt;p&gt;It took about 2 hours to put together. On my machine, the batch itself finished in under 3 minutes once everything was set up.&lt;/p&gt;

&lt;p&gt;This is the kind of repeatable workflow I think of as a Terminal Skill: small, documented, reusable automation that turns a messy manual task into one command.&lt;/p&gt;

&lt;p&gt;Here’s the exact structure I used.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I mean by a CLI skill
&lt;/h2&gt;

&lt;p&gt;For me, a CLI skill is a reusable shell workflow with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;input validation&lt;/li&gt;
&lt;li&gt;sensible defaults&lt;/li&gt;
&lt;li&gt;predictable output&lt;/li&gt;
&lt;li&gt;error handling&lt;/li&gt;
&lt;li&gt;lightweight docs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of retyping a long FFmpeg command every time, I run one script and get the same result every time.&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;# Instead of this:&lt;/span&gt;
ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; input.mp4 &lt;span class="nt"&gt;-ss&lt;/span&gt; 00:00:02 &lt;span class="nt"&gt;-to&lt;/span&gt; 00:00:35 &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"scale=1080:1920"&lt;/span&gt; &lt;span class="nt"&gt;-af&lt;/span&gt; &lt;span class="s2"&gt;"loudnorm=I=-14"&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;:v libx264 &lt;span class="nt"&gt;-preset&lt;/span&gt; fast output.mp4

&lt;span class="c"&gt;# I run this:&lt;/span&gt;
./process-short.sh input.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That difference sounds small, but it removes the part that always breaks in real work: remembering the flags, the order, and the output steps.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: List the manual steps first
&lt;/h2&gt;

&lt;p&gt;Before I wrote anything, I wrote down the full workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;trim the first 2 seconds&lt;/li&gt;
&lt;li&gt;cut after 35 seconds&lt;/li&gt;
&lt;li&gt;scale to 1080×1920&lt;/li&gt;
&lt;li&gt;normalize audio to -14 LUFS&lt;/li&gt;
&lt;li&gt;add watermark&lt;/li&gt;
&lt;li&gt;export MP4&lt;/li&gt;
&lt;li&gt;export WebM&lt;/li&gt;
&lt;li&gt;generate a thumbnail&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That gave me a real pipeline instead of a vague automation idea.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Build one script that does the boring work
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;TRIM_START&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"00:00:02"&lt;/span&gt;
&lt;span class="nv"&gt;TRIM_END&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"00:00:35"&lt;/span&gt;
&lt;span class="nv"&gt;RESOLUTION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"1080:1920"&lt;/span&gt;
&lt;span class="nv"&gt;AUDIO_TARGET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"-14"&lt;/span&gt;
&lt;span class="nv"&gt;WATERMARK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"./assets/watermark.png"&lt;/span&gt;
&lt;span class="nv"&gt;THUMB_TIME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"00:00:05"&lt;/span&gt;

&lt;span class="nv"&gt;INPUT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;:?Usage:&lt;span class="p"&gt; process-short.sh &amp;lt;input.mp4&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$INPUT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Error: File '&lt;/span&gt;&lt;span class="nv"&gt;$INPUT&lt;/span&gt;&lt;span class="s2"&gt;' not found."&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nv"&gt;BASENAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;basename&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$INPUT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; .mp4&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;OUTDIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"./output/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASENAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OUTDIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

ffmpeg &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nt"&gt;-ss&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TRIM_START&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-to&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TRIM_END&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$INPUT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"scale=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RESOLUTION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-af&lt;/span&gt; &lt;span class="s2"&gt;"loudnorm=I=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;AUDIO_TARGET&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-c&lt;/span&gt;:v libx264 &lt;span class="nt"&gt;-preset&lt;/span&gt; fast &lt;span class="nt"&gt;-crf&lt;/span&gt; 23 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OUTDIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/trimmed.mp4"&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$WATERMARK&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;ffmpeg &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OUTDIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/trimmed.mp4"&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$WATERMARK&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;-filter_complex&lt;/span&gt; &lt;span class="s2"&gt;"overlay=W-w-20:H-h-20"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OUTDIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASENAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_final.mp4"&lt;/span&gt;
&lt;span class="k"&gt;else
    &lt;/span&gt;&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OUTDIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/trimmed.mp4"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OUTDIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASENAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_final.mp4"&lt;/span&gt;
&lt;span class="k"&gt;fi

&lt;/span&gt;ffmpeg &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OUTDIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASENAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_final.mp4"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-c&lt;/span&gt;:v libvpx-vp9 &lt;span class="nt"&gt;-crf&lt;/span&gt; 30 &lt;span class="nt"&gt;-b&lt;/span&gt;:v 0 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OUTDIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASENAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.webm"&lt;/span&gt;

ffmpeg &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OUTDIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASENAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_final.mp4"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-ss&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$THUMB_TIME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-frames&lt;/span&gt;:v 1 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OUTDIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASENAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_thumb.jpg"&lt;/span&gt;

&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OUTDIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/trimmed.mp4"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few choices mattered a lot:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;set -euo pipefail&lt;/code&gt; so failures don’t get ignored&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-y&lt;/code&gt; because this is a pipeline, not an interactive tool&lt;/li&gt;
&lt;li&gt;temp file cleanup so output folders stay usable&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 3: Make it batch-capable
&lt;/h2&gt;

&lt;p&gt;One file is a demo. A directory is the real use case.&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;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;INPUT_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;:?Usage:&lt;span class="p"&gt; batch-process.sh &amp;lt;directory&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;PROCESSED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;span class="nv"&gt;FAILED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0

&lt;span class="k"&gt;for &lt;/span&gt;file &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$INPUT_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.mp4&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;continue
    if&lt;/span&gt; ./process-short.sh &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="o"&gt;((&lt;/span&gt;PROCESSED++&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;else
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"FAILED: &lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="o"&gt;((&lt;/span&gt;FAILED++&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;fi
done

&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Batch complete: &lt;/span&gt;&lt;span class="nv"&gt;$PROCESSED&lt;/span&gt;&lt;span class="s2"&gt; processed, &lt;/span&gt;&lt;span class="nv"&gt;$FAILED&lt;/span&gt;&lt;span class="s2"&gt; failed"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is where it actually became useful. I didn’t want a cool script. I wanted to stop babysitting repetitive exports.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4: Add docs, even if it’s just for yourself
&lt;/h2&gt;

&lt;p&gt;I also added a tiny &lt;code&gt;SKILL.md&lt;/code&gt; with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what the script does&lt;/li&gt;
&lt;li&gt;requirements&lt;/li&gt;
&lt;li&gt;usage&lt;/li&gt;
&lt;li&gt;config variables&lt;/li&gt;
&lt;li&gt;output files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That sounds boring, but it matters. A script without docs becomes archaeology in two weeks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 5: Test annoying edge cases
&lt;/h2&gt;

&lt;p&gt;This was the part that caught real bugs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;empty files&lt;/li&gt;
&lt;li&gt;files with missing or unexpected audio tracks&lt;/li&gt;
&lt;li&gt;short clips&lt;/li&gt;
&lt;li&gt;weird filenames with spaces and brackets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That testing found multiple issues immediately. If I had skipped it, the batch version would have failed silently later.&lt;/p&gt;

&lt;p&gt;One of the first things I ran into was how quickly “works on one file” falls apart on real footage. A weird filename, a silent clip, or a shorter-than-expected video is enough to break the whole flow if you never test for it.&lt;/p&gt;

&lt;p&gt;The simplified script above assumes the input has an audio stream. In my real version, I added a small &lt;code&gt;ffprobe&lt;/code&gt; check before applying &lt;code&gt;loudnorm&lt;/code&gt;, because silent clips need a different path.&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;Before:&lt;/strong&gt; most of an afternoon for 16 videos&lt;br&gt;&lt;br&gt;
&lt;strong&gt;After:&lt;/strong&gt; one command, then the machine does the repetitive part&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./batch-process.sh ./raw-videos/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s still less flexible than Premiere. If I want one-off polish, I’ll still do it manually.&lt;/p&gt;

&lt;p&gt;But for repeatable batch work, the tradeoff is absolutely worth it.&lt;/p&gt;

&lt;p&gt;That’s why I like building CLI skills.&lt;/p&gt;

&lt;p&gt;Not because they’re clever. Because they turn something fragile and repetitive into something boring and reliable.&lt;/p&gt;

&lt;p&gt;If you build little terminal workflows or CLI skills like this too, I’d genuinely love to hear what you’ve automated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What would you automate first?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>cli</category>
      <category>tutorial</category>
      <category>devtools</category>
    </item>
    <item>
      <title>MCP Is Not the Product — Reusable Skills Are</title>
      <dc:creator>Alex Shev</dc:creator>
      <pubDate>Tue, 24 Mar 2026 22:20:07 +0000</pubDate>
      <link>https://dev.to/alexshev/mcp-is-not-the-product-reusable-skills-are-27fp</link>
      <guid>https://dev.to/alexshev/mcp-is-not-the-product-reusable-skills-are-27fp</guid>
      <description>&lt;p&gt;Right now, a lot of people are talking about MCP.&lt;/p&gt;

&lt;p&gt;And I get why.&lt;/p&gt;

&lt;p&gt;It’s a clean idea: connect an AI agent to tools, data, and actions through a standard interface, and suddenly the model can actually do things.&lt;/p&gt;

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

&lt;p&gt;But I think a lot of people are still confusing the plumbing with the product.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MCP is useful. MCP is not the product.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The product is what happens after the connection exists.&lt;/p&gt;

&lt;p&gt;The product is a reusable skill.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tools are not enough
&lt;/h2&gt;

&lt;p&gt;Giving an agent access to tools sounds powerful.&lt;/p&gt;

&lt;p&gt;But in practice, raw tool access is messy.&lt;/p&gt;

&lt;p&gt;If you just hand an agent ten tools, you usually get one of these outcomes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it uses the wrong one&lt;/li&gt;
&lt;li&gt;it uses the right one in the wrong order&lt;/li&gt;
&lt;li&gt;it calls the same thing three times with weak assumptions&lt;/li&gt;
&lt;li&gt;it produces output that technically worked, but isn’t reusable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s because tools are still too low-level.&lt;/p&gt;

&lt;p&gt;A tool is a capability.&lt;br&gt;
A skill is a workflow.&lt;/p&gt;

&lt;p&gt;That difference is everything.&lt;/p&gt;


&lt;h2&gt;
  
  
  A simple example
&lt;/h2&gt;

&lt;p&gt;I’ve seen this in boring, practical work more than once.&lt;/p&gt;

&lt;p&gt;An agent with raw shell access and FFmpeg access can absolutely process a video.&lt;/p&gt;

&lt;p&gt;But “can process a video” is not the same as “can reliably produce the same short-form output every time.”&lt;/p&gt;

&lt;p&gt;The raw-tool version tends to drift:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;wrong trim point&lt;/li&gt;
&lt;li&gt;audio forgotten&lt;/li&gt;
&lt;li&gt;watermark missing&lt;/li&gt;
&lt;li&gt;output naming inconsistent&lt;/li&gt;
&lt;li&gt;thumbnail skipped&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The skill version is much narrower, but much more useful.&lt;/p&gt;

&lt;p&gt;It knows the sequence.&lt;br&gt;
It knows the defaults.&lt;br&gt;
It knows what “done” looks like.&lt;/p&gt;

&lt;p&gt;That’s the part people actually want in production.&lt;/p&gt;

&lt;p&gt;Not possibility.&lt;br&gt;
Reliability.&lt;/p&gt;


&lt;h2&gt;
  
  
  What a skill actually is
&lt;/h2&gt;

&lt;p&gt;A skill is not just “the agent can run a command.”&lt;/p&gt;

&lt;p&gt;A useful skill packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the goal&lt;/li&gt;
&lt;li&gt;the right sequence of actions&lt;/li&gt;
&lt;li&gt;defaults&lt;/li&gt;
&lt;li&gt;constraints&lt;/li&gt;
&lt;li&gt;output expectations&lt;/li&gt;
&lt;li&gt;failure handling&lt;/li&gt;
&lt;li&gt;context about when to use it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Compare these two ideas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Tool: FFmpeg is available
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Skill: Turn a raw clip into a 1080x1920 short with trimmed intro, normalized audio, watermark, and thumbnail
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second one is what people actually want.&lt;/p&gt;

&lt;p&gt;No one wakes up thinking:&lt;br&gt;
“I hope my agent has access to a media binary.”&lt;/p&gt;

&lt;p&gt;They want the result.&lt;/p&gt;




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

&lt;p&gt;The current wave of agent demos still over-indexes on tool access.&lt;/p&gt;

&lt;p&gt;You see a lot of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;database access&lt;/li&gt;
&lt;li&gt;filesystem access&lt;/li&gt;
&lt;li&gt;browser access&lt;/li&gt;
&lt;li&gt;shell access&lt;/li&gt;
&lt;li&gt;API access&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s all necessary.&lt;br&gt;
But it’s still not enough.&lt;/p&gt;

&lt;p&gt;Because once the novelty wears off, teams ask a more practical question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can this do the same useful task reliably more than once?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That’s where most agents still fall apart.&lt;/p&gt;

&lt;p&gt;They can improvise.&lt;br&gt;
They can explore.&lt;br&gt;
They can sometimes solve a task.&lt;/p&gt;

&lt;p&gt;But reliable repeated execution comes from skills.&lt;/p&gt;

&lt;p&gt;Skills are what turn “the agent figured it out once” into “the agent can do this whenever I need it.”&lt;/p&gt;




&lt;h2&gt;
  
  
  MCP helps. Skills deliver.
&lt;/h2&gt;

&lt;p&gt;This is why I think the framing matters.&lt;/p&gt;

&lt;p&gt;MCP is important because it standardizes access.&lt;/p&gt;

&lt;p&gt;That’s good.&lt;/p&gt;

&lt;p&gt;But once access is standardized, the real differentiation shifts somewhere else:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;which workflows are packaged well&lt;/li&gt;
&lt;li&gt;which tasks are reusable&lt;/li&gt;
&lt;li&gt;which skills are trustworthy&lt;/li&gt;
&lt;li&gt;which outputs are predictable&lt;/li&gt;
&lt;li&gt;which agent behaviors are actually worth repeating&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In other words:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MCP gives agents hands. Skills give them habits.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And habits are what make a system valuable.&lt;/p&gt;




&lt;h2&gt;
  
  
  The more useful pattern
&lt;/h2&gt;

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

&lt;ul&gt;
&lt;li&gt;use MCP to expose capabilities&lt;/li&gt;
&lt;li&gt;use skills to package outcomes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That way the agent is not just connected.&lt;br&gt;
It is directed.&lt;/p&gt;

&lt;p&gt;And that is a much more practical way to build.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I care about this
&lt;/h2&gt;

&lt;p&gt;This is exactly why I’m bullish on skill-based systems.&lt;/p&gt;

&lt;p&gt;Because once you start packaging repeatable terminal workflows into reusable skills, a lot of noisy AI hype suddenly becomes much simpler.&lt;/p&gt;

&lt;p&gt;You stop asking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what tools can this model access?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And start asking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what useful work can this system repeat reliably?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is a better question.&lt;/p&gt;

&lt;p&gt;And in my experience, it leads to much better products.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tools unlock possibility. Skills unlock reliability.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And reliability is what people actually pay for.&lt;/p&gt;

&lt;p&gt;If you want to see how we think about packaging repeatable terminal workflows into reusable skills, that’s exactly what we’re building at &lt;a href="https://terminalskills.io" rel="noopener noreferrer"&gt;Terminal Skills&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>mcp</category>
      <category>product</category>
    </item>
    <item>
      <title>How I Built a CLI Skill to Batch-Process YouTube Shorts</title>
      <dc:creator>Alex Shev</dc:creator>
      <pubDate>Wed, 18 Mar 2026 04:16:33 +0000</pubDate>
      <link>https://dev.to/alexshev/how-i-built-a-cli-skill-to-batch-process-youtube-shorts-1i68</link>
      <guid>https://dev.to/alexshev/how-i-built-a-cli-skill-to-batch-process-youtube-shorts-1i68</guid>
      <description>&lt;p&gt;Last month, I had to process 16 YouTube Shorts.&lt;/p&gt;

&lt;p&gt;Trim intros. Normalize audio. Add watermarks. Export multiple formats. Generate thumbnails.&lt;/p&gt;

&lt;p&gt;Doing that manually in Premiere would have taken me most of an afternoon.&lt;/p&gt;

&lt;p&gt;So I built a CLI skill instead.&lt;/p&gt;

&lt;p&gt;It took about 2 hours to put together. On my machine, the batch itself finished in under 3 minutes once everything was set up.&lt;/p&gt;

&lt;p&gt;Here’s the exact structure I used.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I mean by a CLI skill
&lt;/h2&gt;

&lt;p&gt;For me, a CLI skill is a reusable shell workflow with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;input validation&lt;/li&gt;
&lt;li&gt;sensible defaults&lt;/li&gt;
&lt;li&gt;predictable output&lt;/li&gt;
&lt;li&gt;error handling&lt;/li&gt;
&lt;li&gt;lightweight docs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of retyping a long FFmpeg command every time, I run one script and get the same result every time.&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;# Instead of this:&lt;/span&gt;
ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; input.mp4 &lt;span class="nt"&gt;-ss&lt;/span&gt; 00:00:02 &lt;span class="nt"&gt;-to&lt;/span&gt; 00:00:35 &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"scale=1080:1920"&lt;/span&gt; &lt;span class="nt"&gt;-af&lt;/span&gt; &lt;span class="s2"&gt;"loudnorm=I=-14"&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;:v libx264 &lt;span class="nt"&gt;-preset&lt;/span&gt; fast output.mp4

&lt;span class="c"&gt;# I run this:&lt;/span&gt;
./process-short.sh input.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That difference sounds small, but it removes the part that always breaks in real work: remembering the flags, the order, and the output steps.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: List the manual steps first
&lt;/h2&gt;

&lt;p&gt;Before I wrote anything, I wrote down the full workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;trim the first 2 seconds&lt;/li&gt;
&lt;li&gt;cut after 35 seconds&lt;/li&gt;
&lt;li&gt;scale to 1080×1920&lt;/li&gt;
&lt;li&gt;normalize audio to -14 LUFS&lt;/li&gt;
&lt;li&gt;add watermark&lt;/li&gt;
&lt;li&gt;export MP4&lt;/li&gt;
&lt;li&gt;export WebM&lt;/li&gt;
&lt;li&gt;generate a thumbnail&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That gave me a real pipeline instead of a vague automation idea.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Build one script that does the boring work
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;TRIM_START&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"00:00:02"&lt;/span&gt;
&lt;span class="nv"&gt;TRIM_END&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"00:00:35"&lt;/span&gt;
&lt;span class="nv"&gt;RESOLUTION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"1080:1920"&lt;/span&gt;
&lt;span class="nv"&gt;AUDIO_TARGET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"-14"&lt;/span&gt;
&lt;span class="nv"&gt;WATERMARK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"./assets/watermark.png"&lt;/span&gt;
&lt;span class="nv"&gt;THUMB_TIME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"00:00:05"&lt;/span&gt;

&lt;span class="nv"&gt;INPUT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;:?Usage:&lt;span class="p"&gt; process-short.sh &amp;lt;input.mp4&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$INPUT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Error: File '&lt;/span&gt;&lt;span class="nv"&gt;$INPUT&lt;/span&gt;&lt;span class="s2"&gt;' not found."&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nv"&gt;BASENAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;basename&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$INPUT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; .mp4&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;OUTDIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"./output/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASENAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OUTDIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

ffmpeg &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nt"&gt;-ss&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TRIM_START&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-to&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TRIM_END&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$INPUT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"scale=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RESOLUTION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-af&lt;/span&gt; &lt;span class="s2"&gt;"loudnorm=I=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;AUDIO_TARGET&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-c&lt;/span&gt;:v libx264 &lt;span class="nt"&gt;-preset&lt;/span&gt; fast &lt;span class="nt"&gt;-crf&lt;/span&gt; 23 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OUTDIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/trimmed.mp4"&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$WATERMARK&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;ffmpeg &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OUTDIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/trimmed.mp4"&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$WATERMARK&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;-filter_complex&lt;/span&gt; &lt;span class="s2"&gt;"overlay=W-w-20:H-h-20"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OUTDIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASENAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_final.mp4"&lt;/span&gt;
&lt;span class="k"&gt;else
    &lt;/span&gt;&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OUTDIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/trimmed.mp4"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OUTDIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASENAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_final.mp4"&lt;/span&gt;
&lt;span class="k"&gt;fi

&lt;/span&gt;ffmpeg &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OUTDIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASENAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_final.mp4"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-c&lt;/span&gt;:v libvpx-vp9 &lt;span class="nt"&gt;-crf&lt;/span&gt; 30 &lt;span class="nt"&gt;-b&lt;/span&gt;:v 0 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OUTDIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASENAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.webm"&lt;/span&gt;

ffmpeg &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OUTDIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASENAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_final.mp4"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-ss&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$THUMB_TIME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-frames&lt;/span&gt;:v 1 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OUTDIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASENAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_thumb.jpg"&lt;/span&gt;

&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OUTDIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/trimmed.mp4"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few choices mattered a lot:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;set -euo pipefail&lt;/code&gt; so failures don’t get ignored&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-y&lt;/code&gt; because this is a pipeline, not an interactive tool&lt;/li&gt;
&lt;li&gt;temp file cleanup so output folders stay usable&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 3: Make it batch-capable
&lt;/h2&gt;

&lt;p&gt;One file is a demo. A directory is the real use case.&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;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;INPUT_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;:?Usage:&lt;span class="p"&gt; batch-process.sh &amp;lt;directory&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;PROCESSED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;span class="nv"&gt;FAILED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0

&lt;span class="k"&gt;for &lt;/span&gt;file &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$INPUT_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.mp4&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;continue
    if&lt;/span&gt; ./process-short.sh &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="o"&gt;((&lt;/span&gt;PROCESSED++&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;else
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"FAILED: &lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="o"&gt;((&lt;/span&gt;FAILED++&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;fi
done

&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Batch complete: &lt;/span&gt;&lt;span class="nv"&gt;$PROCESSED&lt;/span&gt;&lt;span class="s2"&gt; processed, &lt;/span&gt;&lt;span class="nv"&gt;$FAILED&lt;/span&gt;&lt;span class="s2"&gt; failed"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is where it actually became useful. I didn’t want a cool script. I wanted to stop babysitting repetitive exports.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4: Add docs, even if it’s just for yourself
&lt;/h2&gt;

&lt;p&gt;I also added a tiny &lt;code&gt;SKILL.md&lt;/code&gt; with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what the script does&lt;/li&gt;
&lt;li&gt;requirements&lt;/li&gt;
&lt;li&gt;usage&lt;/li&gt;
&lt;li&gt;config variables&lt;/li&gt;
&lt;li&gt;output files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That sounds boring, but it matters. A script without docs becomes archaeology in two weeks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 5: Test annoying edge cases
&lt;/h2&gt;

&lt;p&gt;This was the part that caught real bugs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;empty files&lt;/li&gt;
&lt;li&gt;videos without audio&lt;/li&gt;
&lt;li&gt;short clips&lt;/li&gt;
&lt;li&gt;weird filenames with spaces and brackets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That testing found multiple issues immediately. If I had skipped it, the batch version would have failed silently later.&lt;/p&gt;

&lt;p&gt;One of the first things I ran into was how quickly “works on one file” falls apart on real footage. A weird filename, a silent clip, or a shorter-than-expected video is enough to break the whole flow if you never test for it.&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;Before:&lt;/strong&gt; most of an afternoon for 16 videos&lt;br&gt;&lt;br&gt;
&lt;strong&gt;After:&lt;/strong&gt; one command, then the machine does the repetitive part&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./batch-process.sh ./raw-videos/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s still less flexible than Premiere. If I want one-off polish, I’ll still do it manually.&lt;/p&gt;

&lt;p&gt;But for repeatable batch work, the tradeoff is absolutely worth it.&lt;/p&gt;

&lt;p&gt;That’s why I like building CLI skills.&lt;/p&gt;

&lt;p&gt;Not because they’re clever. Because they turn something fragile and repetitive into something boring and reliable.&lt;/p&gt;

&lt;p&gt;If you build little terminal workflows like this too, I’d genuinely love to hear what you’ve automated. I keep more reusable terminal workflow patterns on &lt;a href="https://terminalskills.io" rel="noopener noreferrer"&gt;Terminal Skills&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What would you automate first?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>automation</category>
      <category>cli</category>
      <category>productivity</category>
      <category>showdev</category>
    </item>
    <item>
      <title>8 FFmpeg Recipes I Use Every Week (That Most Developers Don't Know Exist)</title>
      <dc:creator>Alex Shev</dc:creator>
      <pubDate>Wed, 11 Mar 2026 15:21:39 +0000</pubDate>
      <link>https://dev.to/alexshev/8-ffmpeg-recipes-i-use-every-week-that-most-developers-dont-know-exist-5458</link>
      <guid>https://dev.to/alexshev/8-ffmpeg-recipes-i-use-every-week-that-most-developers-dont-know-exist-5458</guid>
      <description>&lt;p&gt;I've been using FFmpeg almost every day for the past year.&lt;/p&gt;

&lt;p&gt;Mostly for boring real work: cutting Shorts, cleaning voice tracks, exporting web versions, generating thumbnails, and fixing weird media issues at the last minute when something breaks five minutes before publish.&lt;/p&gt;

&lt;p&gt;Most FFmpeg tutorials cover the basics and stop there. These are the commands I actually come back to in production.&lt;/p&gt;

&lt;p&gt;Here are 8 recipes I use constantly. Copy-paste ready.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Extract Audio from Video (and Clean It Up)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Extract audio only&lt;/span&gt;
ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; video.mp4 &lt;span class="nt"&gt;-vn&lt;/span&gt; &lt;span class="nt"&gt;-acodec&lt;/span&gt; libmp3lame &lt;span class="nt"&gt;-q&lt;/span&gt;:a 2 audio.mp3

&lt;span class="c"&gt;# Extract + normalize loudness to broadcast standard&lt;/span&gt;
ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; video.mp4 &lt;span class="nt"&gt;-vn&lt;/span&gt; &lt;span class="nt"&gt;-af&lt;/span&gt; &lt;span class="s2"&gt;"loudnorm=I=-16:TP=-1.5:LRA=11"&lt;/span&gt; &lt;span class="nt"&gt;-ar&lt;/span&gt; 44100 clean_audio.mp3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;When I use it:&lt;/strong&gt; Podcast edits, voiceover cleanup, and those annoying cases where a track sounds fine in headphones but way too quiet after upload. The &lt;code&gt;loudnorm&lt;/code&gt; filter saved me from re-exporting more than once.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Create a GIF from a Video Clip (That Doesn't Look Terrible)
&lt;/h2&gt;

&lt;p&gt;Most GIF conversions look like they were made in 2004. The trick is a two-pass approach with a custom palette.&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;# Generate optimized palette first&lt;/span&gt;
ffmpeg &lt;span class="nt"&gt;-ss&lt;/span&gt; 00:00:05 &lt;span class="nt"&gt;-t&lt;/span&gt; 3 &lt;span class="nt"&gt;-i&lt;/span&gt; video.mp4 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"fps=15,scale=480:-1:flags=lanczos,palettegen"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    palette.png

&lt;span class="c"&gt;# Then use that palette for the GIF&lt;/span&gt;
ffmpeg &lt;span class="nt"&gt;-ss&lt;/span&gt; 00:00:05 &lt;span class="nt"&gt;-t&lt;/span&gt; 3 &lt;span class="nt"&gt;-i&lt;/span&gt; video.mp4 &lt;span class="nt"&gt;-i&lt;/span&gt; palette.png &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-filter_complex&lt;/span&gt; &lt;span class="s2"&gt;"fps=15,scale=480:-1:flags=lanczos[x];[x][1:v]paletteuse"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    output.gif

&lt;span class="c"&gt;# Cleanup&lt;/span&gt;
&lt;span class="nb"&gt;rm &lt;/span&gt;palette.png
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; Single-pass GIFs use a generic 256-color palette. The two-pass method generates a palette optimized for your specific clip.&lt;/p&gt;

&lt;p&gt;I learned this the hard way after making a product GIF that looked fine in preview and terrible after export. Washed-out gradients, ugly banding, weird skin tones. Two-pass fixed it immediately.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Batch Convert an Entire Folder
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Convert all MKV files to MP4 (preserving quality)&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;f &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;.mkv&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;:v libx264 &lt;span class="nt"&gt;-crf&lt;/span&gt; 18 &lt;span class="nt"&gt;-c&lt;/span&gt;:a aac &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="p"&gt;%.mkv&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.mp4"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;

&lt;span class="c"&gt;# Convert all WAV to MP3 at 192kbps&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;f &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;.wav&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-codec&lt;/span&gt;:a libmp3lame &lt;span class="nt"&gt;-b&lt;/span&gt;:a 192k &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="p"&gt;%.wav&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.mp3"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The pattern:&lt;/strong&gt; &lt;code&gt;${f%.ext}&lt;/code&gt; strips the original extension. This is bash string manipulation, not FFmpeg — but it's the glue that makes FFmpeg scriptable.&lt;/p&gt;

&lt;p&gt;This one saved me the most time in practice. Converting one file is nothing. Converting 40 files before lunch is where FFmpeg starts earning its keep.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Split a Video into Equal Chunks
&lt;/h2&gt;

&lt;p&gt;Perfect for breaking long recordings into social-media-sized pieces.&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;# Split into 60-second chunks&lt;/span&gt;
ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; long_video.mp4 &lt;span class="nt"&gt;-c&lt;/span&gt; copy &lt;span class="nt"&gt;-map&lt;/span&gt; 0 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-segment_time&lt;/span&gt; 60 &lt;span class="nt"&gt;-f&lt;/span&gt; segment &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-reset_timestamps&lt;/span&gt; 1 &lt;span class="se"&gt;\&lt;/span&gt;
    chunk_%03d.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt; &lt;code&gt;chunk_000.mp4&lt;/code&gt;, &lt;code&gt;chunk_001.mp4&lt;/code&gt;, &lt;code&gt;chunk_002.mp4&lt;/code&gt;, etc.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;-c copy&lt;/code&gt; flag means no re-encoding — it's almost instant regardless of file size. The split happens at keyframes, so chunks might be slightly longer or shorter than 60 seconds.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Add Subtitles (Burned In)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# From an SRT file&lt;/span&gt;
ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; video.mp4 &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"subtitles=captions.srt:force_style='FontSize=24,FontName=Arial,PrimaryColour=&amp;amp;HFFFFFF,OutlineColour=&amp;amp;H000000,Outline=2'"&lt;/span&gt; output.mp4

&lt;span class="c"&gt;# Quick one-liner subtitle (no SRT file needed)&lt;/span&gt;
ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; video.mp4 &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"drawtext=text='Hello World':fontsize=36:fontcolor=white:x=(w-text_w)/2:y=h-th-40:box=1:boxcolor=black@0.6:boxborderw=8"&lt;/span&gt; output.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pro tip:&lt;/strong&gt; The &lt;code&gt;force_style&lt;/code&gt; parameter in the SRT method lets you override subtitle styling without editing the SRT file. Useful when you get captions from auto-transcription services and need them to look consistent.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Picture-in-Picture (Two Videos Overlaid)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Main video with small webcam overlay in bottom-right&lt;/span&gt;
ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; main.mp4 &lt;span class="nt"&gt;-i&lt;/span&gt; webcam.mp4 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-filter_complex&lt;/span&gt; &lt;span class="s2"&gt;"[1:v]scale=320:240[pip];[0:v][pip]overlay=W-w-20:H-h-20"&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;
    pip_output.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Variations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Top-left: &lt;code&gt;overlay=20:20&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Center: &lt;code&gt;overlay=(W-w)/2:(H-h)/2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Animated (slide in): &lt;code&gt;overlay='if(lt(t,1),W,W-w-20)':H-h-20&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I use this for tutorial videos — screen recording as the main video, webcam as the PiP.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Speed Up / Slow Down Video
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 2x speed (video + audio)&lt;/span&gt;
ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; input.mp4 &lt;span class="nt"&gt;-filter_complex&lt;/span&gt; &lt;span class="s2"&gt;"[0:v]setpts=0.5*PTS[v];[0:a]atempo=2.0[a]"&lt;/span&gt; &lt;span class="nt"&gt;-map&lt;/span&gt; &lt;span class="s2"&gt;"[v]"&lt;/span&gt; &lt;span class="nt"&gt;-map&lt;/span&gt; &lt;span class="s2"&gt;"[a]"&lt;/span&gt; fast.mp4

&lt;span class="c"&gt;# 0.5x speed (slow motion)&lt;/span&gt;
ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; input.mp4 &lt;span class="nt"&gt;-filter_complex&lt;/span&gt; &lt;span class="s2"&gt;"[0:v]setpts=2.0*PTS[v];[0:a]atempo=0.5[a]"&lt;/span&gt; &lt;span class="nt"&gt;-map&lt;/span&gt; &lt;span class="s2"&gt;"[v]"&lt;/span&gt; &lt;span class="nt"&gt;-map&lt;/span&gt; &lt;span class="s2"&gt;"[a]"&lt;/span&gt; slow.mp4

&lt;span class="c"&gt;# 4x speed (atempo max is 2.0, so chain them)&lt;/span&gt;
ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; input.mp4 &lt;span class="nt"&gt;-filter_complex&lt;/span&gt; &lt;span class="s2"&gt;"[0:v]setpts=0.25*PTS[v];[0:a]atempo=2.0,atempo=2.0[a]"&lt;/span&gt; &lt;span class="nt"&gt;-map&lt;/span&gt; &lt;span class="s2"&gt;"[v]"&lt;/span&gt; &lt;span class="nt"&gt;-map&lt;/span&gt; &lt;span class="s2"&gt;"[a]"&lt;/span&gt; 4x.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The gotcha:&lt;/strong&gt; &lt;code&gt;setpts&lt;/code&gt; changes video speed, &lt;code&gt;atempo&lt;/code&gt; changes audio speed. They're separate filters. If you only use &lt;code&gt;setpts&lt;/code&gt;, you get a fast video with normal-speed audio — which is funny exactly once.&lt;/p&gt;

&lt;p&gt;Also: &lt;code&gt;atempo&lt;/code&gt; only accepts values between 0.5 and 2.0. For 4x, you chain two &lt;code&gt;atempo=2.0&lt;/code&gt; filters. I still have to look that up sometimes because it’s one of those FFmpeg details that never stays in my head.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Generate a Video from Images (Slideshow / Timelapse)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# From numbered images (img001.png, img002.png, etc.)&lt;/span&gt;
ffmpeg &lt;span class="nt"&gt;-framerate&lt;/span&gt; 24 &lt;span class="nt"&gt;-i&lt;/span&gt; img%03d.png &lt;span class="nt"&gt;-c&lt;/span&gt;:v libx264 &lt;span class="nt"&gt;-pix_fmt&lt;/span&gt; yuv420p slideshow.mp4

&lt;span class="c"&gt;# From a folder of images (simple slideshow)&lt;/span&gt;
ffmpeg &lt;span class="nt"&gt;-framerate&lt;/span&gt; 1/3 &lt;span class="nt"&gt;-pattern_type&lt;/span&gt; glob &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'*.jpg'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-c&lt;/span&gt;:v libx264 &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"fps=25,format=yuv420p"&lt;/span&gt; &lt;span class="nt"&gt;-pix_fmt&lt;/span&gt; yuv420p &lt;span class="se"&gt;\&lt;/span&gt;
    slideshow.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;When I use it:&lt;/strong&gt; Generating timelapse videos from screenshot sequences. Also useful for turning design mockups into a quick presentation video.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;-framerate 1/3&lt;/code&gt; means each image shows for 3 seconds. Change the denominator to control display time.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Cheat Sheet
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Key flags&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Extract audio&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;-vn&lt;/code&gt; (no video)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No re-encode&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-c copy&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quality control&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;-crf 18&lt;/code&gt; (lower = better, 0-51)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Normalize audio&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-af "loudnorm=I=-16"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scale video&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-vf "scale=1920:1080"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trim&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-ss START -to END&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Overwrite&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-y&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you want more of these, I keep a small collection of terminal-first FFmpeg patterns on &lt;a href="https://terminalskills.io" rel="noopener noreferrer"&gt;terminalskills.io&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;What's your go-to FFmpeg recipe?&lt;/strong&gt; Mine is still the two-pass GIF trick — not glamorous, but I use it constantly because bad GIF exports are way more common than they should be. If you have a better one, drop it in the comments 👇&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
