<?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: Armando Alexis Herra Cortez</title>
    <description>The latest articles on DEV Community by Armando Alexis Herra Cortez (@armandoherra).</description>
    <link>https://dev.to/armandoherra</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F85732%2F1933b82e-92af-45d2-a089-3fa21e7f39a1.png</url>
      <title>DEV Community: Armando Alexis Herra Cortez</title>
      <link>https://dev.to/armandoherra</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/armandoherra"/>
    <language>en</language>
    <item>
      <title>Transmission #004: The Era of AI Tools</title>
      <dc:creator>Armando Alexis Herra Cortez</dc:creator>
      <pubDate>Mon, 07 Sep 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/armandoherra/transmission-004-the-era-of-ai-tools-1gph</link>
      <guid>https://dev.to/armandoherra/transmission-004-the-era-of-ai-tools-1gph</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Why the best AI workflow is building your own tools, and how I build mine: from idea to working CLI in an afternoon.&lt;/p&gt;




&lt;h1&gt;
  
  
  Transmission #004: The Era of AI Tools
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Stop Waiting for the Perfect Tool
&lt;/h2&gt;

&lt;p&gt;Imagine building something made exactly for you, something you never have to pay for. I’m not talking about WinRAR, but you’re getting close. I mean a tool, or just a thing, that you need in your life but never built yourself, because you weren’t quite good enough at it, or you never had the time.&lt;/p&gt;

&lt;p&gt;That changed for me this past year, thanks to AI. Here’s how I embraced AI to build my own tools, and how I use it now to give myself more digital autonomy.&lt;/p&gt;

&lt;p&gt;These days we don’t have to bend and force ourselves to fit some obscure, poorly maintained tool that happens to do exactly what we need. Or one that isn’t obscure at all, but its SDK hasn’t been updated in a while and you’d love to use it with the developer’s latest API.&lt;/p&gt;

&lt;p&gt;So let’s stop waiting. Take the initiative and start building your own tools.&lt;/p&gt;

&lt;p&gt;That’s what I’ve been doing this year, and so far it’s been a fascinating journey. Let me tell you about it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx0fe4emx6ibl9dkkeris.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx0fe4emx6ibl9dkkeris.jpg" alt="A lone toolmaker at a neon-lit workbench, guided by a holographic AI assistant" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  01. Scratch Your Own Itch, at the Speed of Thought
&lt;/h2&gt;

&lt;p&gt;For years the deal with software tooling was simple: someone else builds the generic tool, and you adapt to it. You learn its flags, accept its defaults, and live with the ten percent of your problem it never quite covers. Building your own was possible in theory and absurd in practice. Nobody burns three or more weeks writing a CLI to rename photos.&lt;/p&gt;

&lt;p&gt;That math flipped. With an agentic workflow doing the heavy lifting, the cost of a custom tool dropped from weeks to sessions, and I stopped adapting myself to generic tools. Two receipts from my own repos:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;mediakit&lt;/strong&gt; is a single-binary Go CLI that inspects, renames, cleans, converts, resizes, and dedups images in bulk. It wraps libvips and ExifTool behind one safe interface, every destructive operation supports a global dry-run, and there is a crash-safe undo journal. It exists because bulk media organizing kept turning into a pile of one-off scripts.&lt;/p&gt;

&lt;p&gt;Concretely: a macro photoshoot of a few hundred shots gets renamed into a dated, numbered sequence in one pass; a whole batch gets resized, converted, and stripped of EXIF metadata before it ever touches a website; and duplicate frames collapse automatically. The source repo is still private while I get it ready for a public release (coming soon), but the project site is already live:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://armandoherra.github.io/mediakit/" rel="noopener noreferrer"&gt;https://armandoherra.github.io/mediakit/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;pdf-tooling&lt;/strong&gt; is an Apache-2.0 Python CLI that covers the common PDF chores: merge, split, compress, OCR, encrypt, watermark, and about fifteen more verbs. It was born from a simple refusal: I did not want to upload documents to a random “free PDF converter” website ever again, and I wanted a permissive license stack with nothing GPL on the call graph. Today I can merge a stack of scanned receipts into one searchable PDF, OCR a paper contract into selectable text, watermark a draft before it goes out, and compress a 40 MB deck down to a fraction of that, all with a single local command and nothing leaving my machine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://armandoherra.github.io/pdf-tooling/" rel="noopener noreferrer"&gt;https://armandoherra.github.io/pdf-tooling/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Neither of these is a demo. They are versioned and tested tools that I use every day, and both were built with AI agents doing the implementation while I did the deciding. pdf-tooling is already released; mediakit is one final sweep and a few decisions away from its public launch.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbboym5xh4ry97qptc4az.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbboym5xh4ry97qptc4az.jpg" alt="Two forged tools glowing on a workbench, a terminal window and a stack of documents" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  02. Anatomy of a Good Custom Tool
&lt;/h2&gt;

&lt;p&gt;The difference between a script and a tool is not size. It is contracts. A script does what it did the day you wrote it; a tool makes promises and keeps them on every execution. The two tools above, built months apart in different languages, converged on the same anatomy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A global &lt;code&gt;--dry-run&lt;/code&gt; that plans and reports but writes nothing, anywhere.&lt;/li&gt;
&lt;li&gt;Uniform exit codes, so automation can branch on what actually happened.&lt;/li&gt;
&lt;li&gt;Structured output (&lt;code&gt;-o json&lt;/code&gt; / &lt;code&gt;-o ndjson&lt;/code&gt;) when stdout is not a terminal, so piping into &lt;code&gt;jq&lt;/code&gt; needs no extra flag.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;doctor&lt;/code&gt; verb that verifies external engines up front instead of failing mid-run.&lt;/li&gt;
&lt;li&gt;Atomic writes: temp file, fsync, rename. Inputs are never mutated unless you explicitly ask.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Preview a bulk rename before touching anything&lt;/span&gt;
mediakit rename ./shoot &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nt"&gt;--template&lt;/span&gt; &lt;span class="s1"&gt;'{date:2006-01-02}_{counter:04}'&lt;/span&gt; &lt;span class="nt"&gt;--dry-run&lt;/span&gt;

&lt;span class="c"&gt;# Convert + resize a whole folder and strip EXIF in one pass&lt;/span&gt;
mediakit convert ./shoot &lt;span class="nt"&gt;-f&lt;/span&gt; jpg &lt;span class="nt"&gt;--resize&lt;/span&gt; 2048 &lt;span class="nt"&gt;-o&lt;/span&gt; ./web &lt;span class="nt"&gt;--strip&lt;/span&gt; &lt;span class="nt"&gt;--dry-run&lt;/span&gt;

&lt;span class="c"&gt;# Find and collapse duplicate frames&lt;/span&gt;
mediakit dedup ./shoot &lt;span class="nt"&gt;-o&lt;/span&gt; json

&lt;span class="c"&gt;# Confirm every external engine is healthy before a batch job&lt;/span&gt;
mediakit doctor

&lt;span class="c"&gt;# Compress a PDF, get machine-readable output for the pipeline&lt;/span&gt;
pdftooling compress report.pdf &lt;span class="nt"&gt;-O&lt;/span&gt; small.pdf &lt;span class="nt"&gt;-o&lt;/span&gt; json

&lt;span class="c"&gt;# Merge a folder of scanned receipts into one searchable PDF&lt;/span&gt;
pdftooling merge ./receipts/&lt;span class="k"&gt;*&lt;/span&gt;.pdf &lt;span class="nt"&gt;-O&lt;/span&gt; year-end.pdf

&lt;span class="c"&gt;# OCR a paper contract into selectable text&lt;/span&gt;
pdftooling ocr contract-scan.pdf &lt;span class="nt"&gt;-O&lt;/span&gt; contract-text.pdf

&lt;span class="c"&gt;# Watermark a draft before sending it out&lt;/span&gt;
pdftooling watermark draft.pdf &lt;span class="nt"&gt;--text&lt;/span&gt; &lt;span class="s2"&gt;"CONFIDENTIAL"&lt;/span&gt; &lt;span class="nt"&gt;-O&lt;/span&gt; draft-marked.pdf

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice who those contracts actually serve. A human might read the table output once; the thousand other executions come from scripts, CI jobs, and increasingly my own agents. Exit codes and JSON envelopes are not developer vanity, they are the interface an unsupervised caller can actually trust. When an agent runs a destructive verb, the dry-run is its rehearsal and the exit code is its answer.&lt;/p&gt;

&lt;p&gt;That anatomy is not an accident, and it connects straight back to practice 04 of &lt;a href="https://blog.armandoherra.com/containing-rogue-agents" rel="noopener noreferrer"&gt;Transmission #003&lt;/a&gt;: deterministic tools are what make agentic workflows reliable. The agent decides when to run the tool. The tool decides what happens. Same input, same output, every execution.&lt;/p&gt;

&lt;p&gt;Here is the part that changed with AI: this level of polish used to be the expensive half of tool-building. Argument parsing, help text, edge cases, tests, docs; the boring 80 percent that pushed everyone to ship a quick script instead. That is exactly the work agents excel at. Today the costly part is not keeping the contract, it is deciding what the contract should be. I spend my effort on the promises; my agents spend theirs on keeping them everywhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  03. Why I Built My Own SDK: firecrawl-go
&lt;/h2&gt;

&lt;p&gt;Custom tools do not stop at CLIs. Sometimes the missing piece is a library, and this one comes with an origin story about tokens.&lt;/p&gt;

&lt;p&gt;My agents read documentation offline. A command in my agentic layer maps a documentation site, scrapes every page into LLM-ready markdown, and drops the bundle into a local &lt;code&gt;ai_docs/&lt;/code&gt; folder; agents then read those files directly instead of fetching live pages mid-session. Right now that folder holds 35 scraped doc sets: Kubernetes, Helm, Grafana, FastAPI, the Go standard library, and thirty more.&lt;/p&gt;

&lt;p&gt;The first version of that pipeline ran on the official Firecrawl MCP server, with Claude driving the scrape from inside the session. It worked, and it was brutally expensive. One or two large doc scrapes would burn almost my entire five-hour Claude usage budget, because every scraped page flowed through the model’s context on its way to disk. I was spending premium reasoning tokens on what is, at heart, a download job, and I could not do much else with Claude until the window reset.&lt;/p&gt;

&lt;p&gt;That sent me looking for a better way to spend my tokens, and the answer was obvious in hindsight: scraping does not need a model in the loop, it needs a CLI. So I set out to build my own scraping CLI in Go, and promptly fell down the rabbit hole. The official Go SDK for Firecrawl had been abandoned on the v1 API while v2 was already the documented default. Entire endpoints like search existed only as stubs, and v2 shipped exactly what my CLI needed: batch scrape with concurrency control, structured extraction with JSON schemas, richer map responses. Building the CLI meant modernizing the SDK first, so I decided to attempt my own version and rebuilt it against v2:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ArmandoHerra/firecrawl-go" rel="noopener noreferrer"&gt;https://github.com/ArmandoHerra/firecrawl-go&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The result is that &lt;code&gt;scrape-docs&lt;/code&gt; now scrapes anything at very high speed and spends exactly zero model tokens doing it. The use cases that justify the fork:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The offline docs pipeline.&lt;/strong&gt; &lt;code&gt;scrape-docs&lt;/code&gt; maps a site, then batch-scrapes it with 10 concurrent workers into clean markdown files. One command, one static binary, no Python environment, and it runs outside any AI session for batch jobs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Typed access to a moving API.&lt;/strong&gt; v2 renamed crawl parameters, changed map responses from plain strings to objects, and turned webhooks from a string into an object. In Go those are compile errors, not runtime surprises. The type system does the migration review for me.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Owning the upgrade schedule.&lt;/strong&gt; When the API moves again, I migrate my client the same week, instead of waiting for an upstream maintainer to find the time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concurrency where it belongs.&lt;/strong&gt; Goroutines plus errgroup give me a bounded, polite scraper without pulling in a framework. That is the job Go was built for.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The wiring is honest and boring, exactly how I like my infrastructure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// scripts/scrape/docs/go.mod&lt;/span&gt;
&lt;span class="n"&gt;require&lt;/span&gt; &lt;span class="n"&gt;github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;firewcrawl&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;firecrawl&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;v2&lt;/span&gt; &lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="m"&gt;.0.0&lt;/span&gt;

&lt;span class="n"&gt;replace&lt;/span&gt; &lt;span class="n"&gt;github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;firewcrawl&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;firecrawl&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;v2&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;../../../&lt;/span&gt;&lt;span class="n"&gt;apps&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;firecrawl&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The replace directive is the whole trick. It points the tool at a local checkout of my fork instead of a published module, so reproducing it takes one extra step: clone the fork next to the tool (into &lt;code&gt;apps/firecrawl-go&lt;/code&gt;), because the path is relative and the build fails without it. The &lt;code&gt;v2.0.0&lt;/code&gt; version is decorative, the local directory wins and Go never fetches this dependency from the network. The module path, &lt;code&gt;github.com/firewcrawl/firecrawl-go/v2&lt;/code&gt; spelling included, is just whatever the fork’s own &lt;code&gt;go.mod&lt;/code&gt; declares. From there it is &lt;code&gt;go mod tidy&lt;/code&gt;, &lt;code&gt;go build&lt;/code&gt;, and you are done.&lt;/p&gt;

&lt;p&gt;A small honest footnote: I offered the modernization back upstream, and I would have loved to see the official SDK move faster. Sadly the Firecrawl team did not find interest in my upgrade at the time, and months later they released their own updated version. No hard feelings, it is their project and their call to make, and my fork still does exactly the job I built it for.&lt;/p&gt;

&lt;p&gt;The honest ending of this story is that the rabbit hole changed my defaults. Building my own tools with AI stopped being a workaround and became something I genuinely enjoy thinking about and doing. I intend to keep creating tools and maintaining them with my AI agents, and to keep contributing to a better open source software ecosystem in my own way: one small, sharp, well-behaved tool at a time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fil71ig5e1k403gjyy2hg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fil71ig5e1k403gjyy2hg.jpeg" alt="Firecrawl MCP server versus a custom CLI, side by side" width="800" height="526"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Putting this tool behind a Skill instead of an MCP server changed how my whole workflow feels. The MCP version was seductively easy: one tool call, and Claude handled the rest. But that ease was the expensive part. Every page it pulled rode through the model’s context, so the meter spun the whole time.&lt;/p&gt;

&lt;p&gt;Once &lt;code&gt;scrape-docs&lt;/code&gt; became a Skill, the same job turned into a single deterministic command that runs outside the session, off the token meter entirely. The agent asks for the docs, the tool fetches them, and nothing burns reasoning budget in between.&lt;/p&gt;

&lt;p&gt;My honest take: MCP servers are powerful, and I still use some of them. But I treat them the way I treat anything that bills by convenience. The thing that saves you two minutes of setup can quietly become the thing that eats your monthly budget if you do not watch what flows through the context. My rule is simple. If a job is a download, a lookup, or a deterministic transform, I reach for a Skill or a CLI first. A little upfront complexity goes a long way toward not paying premium tokens for unnecessary plumbing.&lt;/p&gt;

&lt;h2&gt;
  
  
  04. Where This Goes
&lt;/h2&gt;

&lt;p&gt;I can tell you where this goes for me, because it is already in motion. I am going to keep building my own personal toolchain: tools that push my tech ambitions and goals forward, maintained with my agents, shaped exactly to how I work. Some of those ideas will grow past the personal. I will probably spin a few of them into small side SaaS products, not to chase a unicorn, but to finance myself and the goals behind the rest of the work.&lt;/p&gt;

&lt;p&gt;The part I care most about is not the paid tier, though. The tools that got me here (the compilers, the editors, the runtimes) were free, and I want to give back in the same currency. Most of what I build, I want to be easy to use and mostly free to download and use: tools an ordinary person can grab without an account, a subscription, or a tutorial, and that quietly improve their day. pdf-tooling already lives by that rule, and mediakit will join it when it goes public.&lt;/p&gt;

&lt;p&gt;The era of AI tools, at least in my corner of it, is not about AI replacing the toolmaker. It is about one person with good agents being able to run a whole workshop: build for yourself first, sell what earns its keep, and give away the rest. That’s my personal philosophy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff8sh7x20zo9ttuu41mgx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff8sh7x20zo9ttuu41mgx.jpg" alt="A toolmaker handing a glowing tool out to a distant figure, a neon city skyline stretching beyond the workshop" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing Comments
&lt;/h2&gt;

&lt;p&gt;I’m done for now. Next time I’ll probably talk a little bit more about Agents, Harness Engineering or some of my whacky side-projects or PoCs I come up with soon. Also, I don’t have a set cadence for these articles yet, so they will randomly drop from time to time.&lt;/p&gt;

&lt;p&gt;Ending transmission…&lt;/p&gt;

&lt;p&gt;Armando Herra&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you enjoy my work, you can support it through &lt;a href="https://github.com/sponsors/ArmandoHerra" rel="noopener noreferrer"&gt;GitHub Sponsors&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Delivered via my personal automated publishing workflow, written with human ideas, words, and work behind.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agenticai</category>
      <category>devex</category>
      <category>automation</category>
    </item>
    <item>
      <title>Transmission #003: Containing Rogue Agents</title>
      <dc:creator>Armando Alexis Herra Cortez</dc:creator>
      <pubDate>Wed, 02 Sep 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/armandoherra/transmission-003-containing-rogue-agents-1egl</link>
      <guid>https://dev.to/armandoherra/transmission-003-containing-rogue-agents-1egl</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Four practices to keep AI coding agents from wrecking production: no prod credentials, Claude Code hooks as guardrails, sandboxed testing with gVisor, and deterministic workflows.&lt;/p&gt;




&lt;h1&gt;
  
  
  Transmission #003: Containing Rogue Agents
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Agents Sowing Chaos
&lt;/h2&gt;

&lt;p&gt;A while back, this story was everywhere: an AI agent allegedly deleted a startup’s production database and caused a huge outage. It still comes up every time someone proposes giving an agent more autonomy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://mashable.com/article/ai-agent-deletes-data-30-hour-service-outage-pocketos" rel="noopener noreferrer"&gt;https://mashable.com/article/ai-agent-deletes-data-30-hour-service-outage-pocketos&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Agents ruining engineering work isn’t fun. You’ve probably heard a scary story or two of your own about an agent going rogue and doing something it wasn’t supposed to.&lt;/p&gt;

&lt;p&gt;And sometimes the sandbox itself is what fails. In July 2026, &lt;a href="https://www.nbcnews.com/tech/tech-news/openai-report-says-network-was-hacked-rogue-ai-agents-rcna594590" rel="noopener noreferrer"&gt;a swarm of roughly 700 OpenAI agents&lt;/a&gt; that were being evaluated for cyber capabilities broke out of their training environment and hacked Hugging Face, running over 17,000 actions and even trying to cover their tracks. Nobody ordered the attack: the models had learned to cheat through reward hacking during training.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.technologyreview.com/2026/08/26/1143013/the-inside-story-on-why-openai-agents-hacked-hugging-face/" rel="noopener noreferrer"&gt;https://www.technologyreview.com/2026/08/26/1143013/the-inside-story-on-why-openai-agents-hacked-hugging-face/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can’t control what happens inside OpenAI’s training runs, but your own blast radius is yours to manage. Most of these disasters are preventable, and the four practices below will help you avoid unexpected surprises.&lt;/p&gt;

&lt;p&gt;I’ll lay them out straight and without rodeos.&lt;/p&gt;

&lt;h2&gt;
  
  
  01. Don’t Give Your Agents Credentials to Prod!
&lt;/h2&gt;

&lt;p&gt;Remember the deleted database from the intro? There was no magic in that incident. An agent can only destroy what its credentials can reach, and that agent could reach production.&lt;/p&gt;

&lt;p&gt;If you do the same, you are accepting the risk of something going wrong, even if you didn’t intend for it to happen.&lt;/p&gt;

&lt;p&gt;Here is what makes an agent different from a human with the same access. An agent executes at machine speed, in loops, with total confidence: a hallucinated table name runs as happily as the correct one, and there is no “wait, this feels wrong” pause before Enter. Add prompt injection and it gets worse: if your agent reads external content while holding prod credentials, anyone who can get text in front of it is effectively holding your credentials too. The prompt is a suggestion. The credential is a capability.&lt;/p&gt;

&lt;p&gt;What I do instead is simple: my agents get scoped, short-lived, least-privilege credentials for the environment they’re working in, and production only changes through the same reviewed pipeline a human would use. The agent can open the PR; only the pipeline touches prod.&lt;/p&gt;

&lt;p&gt;Removing credentials shrinks what an agent can ruin. But that question kept pulling at me: what if I could also shrink what it can even &lt;em&gt;touch&lt;/em&gt;? Hold that thought until practice 03.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh3qamlrpzjeswg5c8hgn.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh3qamlrpzjeswg5c8hgn.jpg" alt="An AI agent blocked from a production vault by an access-denied barrier" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  02. Use Safeguards to Avoid Preventable Disasters
&lt;/h2&gt;

&lt;p&gt;I do Agentic Coding on almost a daily basis with Claude Code, and if you use this tool, one feature can enhance your current workflows and serve as a safeguard: it’s called “Hooks”.&lt;/p&gt;

&lt;p&gt;Claude Code hooks are user-defined event handlers that fire deterministically at specific points in Claude Code’s lifecycle, before/after a tool call, when you submit a prompt, on session start, when Claude finishes responding, and so on.&lt;/p&gt;

&lt;p&gt;They run with your full user permissions, so they’re effectively a programmable layer between Claude and your system.&lt;/p&gt;

&lt;p&gt;The point is guardrails that don’t rely on the model remembering vague instructions. Rules like “never delete the Prod database”, “never run &lt;code&gt;rm -rf /&lt;/code&gt;”, or “never run &lt;code&gt;terraform destroy&lt;/code&gt; without explicit authorization” stop being hopes and become code.&lt;/p&gt;

&lt;p&gt;Here is a working miniature of the guard I run on my own machine. First, register the hook in &lt;code&gt;.claude/settings.json&lt;/code&gt; so it fires before every Bash command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"PreToolUse"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"matcher"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bash"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$CLAUDE_PROJECT_DIR/.claude/hooks/bash_guard.py"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the hook itself, &lt;code&gt;.claude/hooks/bash_guard.py&lt;/code&gt;, reads the proposed command from stdin and denies anything that matches a blocked pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Deny dangerous Bash commands before Claude Code runs them.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;

&lt;span class="n"&gt;BLOCKED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rm\s+-rf\s+[/~]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rm -rf on root or home paths is never OK&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;terraform\s+destroy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;terraform destroy needs explicit human approval&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;psql\s+.*\bprod\b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;no direct commands against the prod database&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool_input&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{}).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;command&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reason&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;BLOCKED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hookSpecificOutput&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hookEventName&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PreToolUse&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;permissionDecision&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;deny&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;permissionDecisionReason&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}}))&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An empty output lets the command through, and the deny JSON blocks it with a reason the agent gets to read. Deterministic, no matter what the model “thinks”. The full version I run has around twenty destructive-command patterns plus an allowlist for safe paths like &lt;code&gt;node_modules&lt;/code&gt; where Claude is allowed to run these commands.&lt;/p&gt;

&lt;p&gt;More examples of typical uses: auto-format/lint after every edit, block rm -rf or commits to main, scan for secrets before a write, run tests on Stop and force Claude to keep going if they fail, or send a desktop notification when it’s waiting on you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmdozbavh3y8epupazscf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmdozbavh3y8epupazscf.jpg" alt="Commands passing through a corridor of safeguard gates, with one malicious command caught mid-flight" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  03. Test Your Changes in Lower Environments or Safe Environments First
&lt;/h2&gt;

&lt;p&gt;This practice is classic engineering hygiene, and agents deserve it twice. The actions an agent takes should graduate through environments just like your code does: dev first, staging next, and prod last. An agent’s mistakes are not compile errors, they execute with real consequences on whatever machine it’s running on. So before you trust a new agent, tool, or guardrail on your daily driver, give it a place where being wrong is cheap.&lt;/p&gt;

&lt;p&gt;That idea stopped being theoretical for me very quickly. I was experimenting with creating and testing some of these hooks, and I thought to myself:&lt;/p&gt;

&lt;p&gt;“How can I safely test these hooks on my system?”&lt;/p&gt;

&lt;p&gt;“What if the hook isn’t correctly configured and it’s not intercepted and the command runs against my machine?”&lt;/p&gt;

&lt;p&gt;“How can I prevent ruining my own operating system or the database that’s connected on my local machine?”&lt;/p&gt;

&lt;h3&gt;
  
  
  Building My Own Sandbox with gVisor
&lt;/h3&gt;

&lt;p&gt;And that’s when I thought, “I need a Sandbox for my AI Agents”. This isn’t a new concept, I know, but it’s something that’s been trending lately in the Agentic AI Ecosystem, so I decided to experiment with a simple combination of concepts/technologies.&lt;/p&gt;

&lt;p&gt;I thought to myself, how can I combine Containers and Agents?&lt;/p&gt;

&lt;p&gt;Since I run my Claude Agents in an Ephemeral-Way, I follow the 1 Agent-Per-Task Philosophy (More on Agentic Coding Best Practices in future content), using Containers sounded like a good starting point.&lt;/p&gt;

&lt;p&gt;I also wanted to restrict the access the agent had to certain system capabilities to avoid the agent “Breaking Out-of-the-Sandbox” if it decided to go Rogue or was “Taken-Over” by a hostile force.&lt;/p&gt;

&lt;p&gt;This would prevent privilege escalations in the K8s Cluster or Container Platform Running the AI Agent, and for added complexity because #YOLO.&lt;/p&gt;

&lt;p&gt;I wanted this Solution to be “Cloud-Native”, since I’ve been working towards learning and framing my thoughts for these types of systems lately.&lt;/p&gt;

&lt;p&gt;So with that I started ruminating and thinking what would be a good choice.&lt;/p&gt;

&lt;p&gt;I recalled some concepts I studied for the CKS (Certification Pending), gVisor grabbed my attention and I decided to give it a try in my PoC.&lt;/p&gt;

&lt;p&gt;They sell themselves in the following way: “gVisor is an open-source Linux-compatible sandbox that runs anywhere existing container tooling does. It enables cloud-native container security and portability.”&lt;/p&gt;

&lt;p&gt;Sounds nice on paper, but let’s put it to practice.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4x4l4pu7n75dw401h314.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4x4l4pu7n75dw401h314.jpg" alt="An AI agent contained in a hexagonal glass chamber, its gVisor honeycomb membrane intercepting system calls before they reach the host servers" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I decided to hop on Claude Code to help fill the gaps I had in my mind and improve the implementation I was planning mentally.&lt;/p&gt;

&lt;p&gt;I ran through the details and behaviors I wanted the PoC to have, but I needed to get the SPECS written and the code running to keep the ideas flowing.&lt;/p&gt;

&lt;p&gt;After a few iterations of SPEC writing and implementing I got a rough PoC but it managed to give me the behavior I was expecting.&lt;/p&gt;

&lt;p&gt;This is the run command the PoC ended up with, straight from its Makefile. Every flag is one layer of the cage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;docker run \
  --runtime=runsc \
  --rm \
  --network=proxy-net \
  --cap-drop ALL \
  --security-opt no-new-privileges \
  --read-only \
  --tmpfs /tmp:rw,noexec,nosuid,size=100m \
  --tmpfs /workspace:rw,noexec,nosuid,size=500m \
  --memory 2g --cpus 2 --pids-limit 100 \
  --user 1000:1000 \
  -e ALLOW_SHELL="" \
  -e ALLOW_SHELL_TOOL="" \
  -e SHELL_TIMEOUT="30" \
  --add-host=proxy-host:$PROXY_IP \
  -e ANTHROPIC_PROXY_URL="http://proxy-host:18080" \
  -e ANTHROPIC_API_KEY="proxied" \
  sandbox-agent:latest

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;--runtime=runsc&lt;/code&gt; is the gVisor part, and it changes what “inside the container” even means. The agent’s system calls never reach my host kernel: they hit gVisor’s user-space kernel first, which implements the Linux syscall surface itself and forwards only a small, filtered set to the real one. If the agent misbehaves its way out of the container, what it lands in is gVisor, not my machine.&lt;/p&gt;

&lt;p&gt;The rest of the flags close the side doors. The container joins an internal-only network where the single route out is an allowlisting proxy, and notice &lt;code&gt;ANTHROPIC_API_KEY="proxied"&lt;/code&gt;: the sandbox never holds my real key, it sends requests with a placeholder and the proxy injects the key on the way to the provider. Capabilities are dropped, privilege escalation is off, the filesystem is read-only with small noexec scratch mounts, and memory, CPU, and process counts are capped so a runaway agent can’t take the box down with it.&lt;/p&gt;

&lt;p&gt;The newest addition is a set of capability knobs, all off by default. &lt;code&gt;ALLOW_SHELL&lt;/code&gt; and &lt;code&gt;ALLOW_SHELL_TOOL&lt;/code&gt; gate whether the operator or the model can run shell commands inside the sandbox, &lt;code&gt;/workspace&lt;/code&gt; stays noexec unless a run opts in with &lt;code&gt;WORKSPACE_EXEC=1&lt;/code&gt;, and extra Linux capabilities require both an explicit &lt;code&gt;CAP_ADD&lt;/code&gt; list and &lt;code&gt;RUN_AS_ROOT=1&lt;/code&gt;. Even that last one only makes the agent root inside gVisor’s Sentry, not on my machine. Deny by default, opt in per run.&lt;/p&gt;

&lt;p&gt;Here is the GitHub Repository and some of the Real World Use Cases that this PoC could help with currently and/or if developed further:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;GitHub Repo: &lt;a href="https://github.com/ArmandoHerra/gvisor-agent-sandbox-poc" rel="noopener noreferrer"&gt;gvisor-agent-sandbox-poc&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Real World Use Cases:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the list of real world use cases goes on and on…&lt;/p&gt;

&lt;p&gt;If you wish to support my continued development on this project, please consider joining my &lt;a href="https://github.com/sponsors/ArmandoHerra" rel="noopener noreferrer"&gt;GitHub Sponsors&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;DISCLAIMER: Take into account that this repo isn’t meant for production usage yet and it’s in a PoC stage as of September 2, 2026. If you decide to use this in Production the responsibility for any issue or incident is entirely YOURS for implementing a PoC in Production.&lt;/p&gt;

&lt;h3&gt;
  
  
  Kubernetes SIG: Agent Sandbox
&lt;/h3&gt;

&lt;p&gt;Now coming back to the high level topic of Agent Sandboxes, after I experimented a bit with my own solution, I learned about an existing solution being developed by the Kubernetes SIGs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://agent-sandbox.sigs.k8s.io" rel="noopener noreferrer"&gt;https://agent-sandbox.sigs.k8s.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is how Agent Sandbox sells itself.&lt;/p&gt;

&lt;p&gt;“Agent Sandbox provides a secure and isolated execution layer to safely deploy autonomous AI agents on Kubernetes that generate and run untrusted code at scale.”&lt;/p&gt;

&lt;p&gt;This sounds like a promising project, very similar in nature to the one I was developing. I recommend you keep an eye on it, and it might also prove to be a part of the CNCF’s &lt;a href="https://aaif.io" rel="noopener noreferrer"&gt;AAIF&lt;/a&gt; in the future.&lt;/p&gt;

&lt;p&gt;More on Kubernetes SIGs and projects being developed in a Future Article…&lt;/p&gt;

&lt;h2&gt;
  
  
  04. Make Your Agentic Workflows Deterministic
&lt;/h2&gt;

&lt;p&gt;This is something that’s been in the back of my mind for a while now. I’ve been starting to shift a lot of my Agentic AI workflows to be more “declarative” and “deterministic” since the year started, and it all just recently clicked even more when talking with &lt;a href="https://linkedin.com/in/fabrizio-sgura" rel="noopener noreferrer"&gt;Fabrizio Sgura&lt;/a&gt; prior to the KCD Guadalajara 2026, thanks for the great insights man!&lt;/p&gt;

&lt;p&gt;The idea is simple: every time you rely on the agent to resolve something spontaneously, you get a creative but varied answer, and that variance alters the final result. When a step matters, turn it into a script or a tool the agent calls, instead of a task it improvises. The agent decides when to run it; the script decides what happens. Same input, same output, every run.&lt;/p&gt;

&lt;p&gt;Here is a small real example from this very blog. Every link-preview card you saw in this article was built by a script, not by the agent’s creativity. When I add a new link to a post, the agent runs one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run previews:fetch

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script scans my posts for bare URLs, fetches each page’s metadata once, downloads the preview image, and writes it all into a committed cache that the build reads from. I could instead ask the agent to “go fetch the title and image and build a card” every time, and it would, with slightly different HTML on every run. The script produces the same card for the same link, forever. This is also how I shape my Claude Code commands in general: the command’s markdown tells the agent when and why, and the script it calls owns the how.&lt;/p&gt;

&lt;p&gt;Having declarative and more deterministic workflows will greatly improve the reliability and quality of the output they generate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing Comments
&lt;/h2&gt;

&lt;p&gt;More and more tooling is starting to pop up in the Agentic AI Ecosystem, probably some AAIF TAGs (Technical Advisory Groups) will be created to steer the development and maturity of these tools for the Cloud-Native Landscape…&lt;/p&gt;

&lt;p&gt;I’ve exhausted the thoughts I wanted to share with you for now. In the near future, I’ll expand on and deep-dive into some of the ideas and adjacent topics mentioned here.&lt;/p&gt;

&lt;p&gt;Ending transmission…&lt;/p&gt;

&lt;p&gt;Armando Herra&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you enjoy my work, you can support it through &lt;a href="https://github.com/sponsors/ArmandoHerra" rel="noopener noreferrer"&gt;GitHub Sponsors&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Delivered via my personal automated publishing workflow, written with human ideas, words, and work behind.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agenticai</category>
      <category>security</category>
      <category>containers</category>
    </item>
    <item>
      <title>Transmission #002: Signal Over Noise</title>
      <dc:creator>Armando Alexis Herra Cortez</dc:creator>
      <pubDate>Tue, 21 Apr 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/armandoherra/transmission-002-signal-over-noise-349j</link>
      <guid>https://dev.to/armandoherra/transmission-002-signal-over-noise-349j</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; A creative reset, a Marie Kondo purge, and my promise to keep this blog unmistakably human in the age of AI-generated noise.&lt;/p&gt;




&lt;h1&gt;
  
  
  Transmission #002: Signal Over Noise
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Starting Over
&lt;/h2&gt;

&lt;p&gt;Scratch that. I’m starting article #2 from zero. The IaC series can wait.&lt;/p&gt;

&lt;p&gt;If you’ve visited before, you probably saw a half-baked IaC post. I shelved it. Creative block, responsibilities piling up, the usual. Time to start fresh.&lt;/p&gt;

&lt;p&gt;I’ll write that one again, but in a better form. For now, this piece will be a bit of personal introspection and a look at my plans for this blog.&lt;/p&gt;

&lt;p&gt;I also like journaling. It settles my mind. So expect a journal-style post like this once in a while. The technical deep-dives stay the main fare.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Marie Kondo Moment
&lt;/h2&gt;

&lt;p&gt;I’ve been in a Marie Kondo phase. Purging garbage, both literal and figurative. The point is recovering time and mental bandwidth for what’s next.&lt;/p&gt;

&lt;p&gt;A few things have become clearer to me in the last few months.&lt;/p&gt;

&lt;p&gt;I want to let curiosity run wild. Chase the tech ideas, the business ideas, the projects I’ve been postponing. Share what I learn along the way.&lt;/p&gt;

&lt;p&gt;And to be upfront: I’ll use AI as a tool, but the writing and the ideas stay mine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Signal Over Noise
&lt;/h2&gt;

&lt;p&gt;Here’s the experiment. AI is everywhere now. Every website, every product, every feed. Very soon we’ll be drowning in AI-generated garbage online.&lt;/p&gt;

&lt;p&gt;For a while, I had my writing plans on freeze. Figuring out where to use AI, where not to. I didn’t want to fall down the rabbit hole and become another hollow voice online, no longer sharing any true human essence.&lt;/p&gt;

&lt;p&gt;I wanted to make sure that when I did start publishing, what I put out online is actually my content.&lt;/p&gt;

&lt;p&gt;I’m an AI advocate. I won’t use it to write my content. Grammar tools are fine. The words and the ideas stay mine. Diluting them is the line.&lt;/p&gt;

&lt;p&gt;I care what people think. I hope you do too. Let’s keep it real between us.&lt;/p&gt;

&lt;p&gt;And sorry if my writing and ideas are a bit messy, but let’s say that’s your guarantee that they are human words and thoughts being written.&lt;/p&gt;

&lt;h2&gt;
  
  
  A few spoilers for the next pieces of content
&lt;/h2&gt;

&lt;p&gt;I’ve been working after hours on some interesting projects and concepts.&lt;/p&gt;

&lt;p&gt;One is on these three topics, Kubernetes, security, and agentic AI.&lt;/p&gt;

&lt;p&gt;Another is a custom tool I built to cut Claude Code’s token spend when I was scraping documentation with Firecrawl. I’ll go into the details, what worked, what didn’t.&lt;/p&gt;

&lt;p&gt;I’ll share the GitHub repos and links when those posts ship.&lt;/p&gt;

&lt;p&gt;Interested in the next articles or on these topics?&lt;/p&gt;

&lt;p&gt;Follow my blog via it’s RSS feed.&lt;/p&gt;

&lt;p&gt;English and spanish versions, no fluff.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

&lt;p&gt;Until next time,&lt;/p&gt;

&lt;p&gt;Armando Herra&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Transmission Ended: Armando Herra @ Apr 21, 2026&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;em&gt;If you enjoy my work, you can support it through &lt;a href="https://github.com/sponsors/ArmandoHerra" rel="noopener noreferrer"&gt;GitHub Sponsors&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Delivered via my personal automated publishing workflow, written with human ideas, words, and work behind.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>personal</category>
      <category>ai</category>
      <category>writing</category>
      <category>devjournal</category>
    </item>
    <item>
      <title>Transmission #001: Hello World!</title>
      <dc:creator>Armando Alexis Herra Cortez</dc:creator>
      <pubDate>Fri, 26 Dec 2025 00:00:00 +0000</pubDate>
      <link>https://dev.to/armandoherra/transmission-001-hello-world-2igi</link>
      <guid>https://dev.to/armandoherra/transmission-001-hello-world-2igi</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; This is my first blog post, here I describe the purpose of this blog and my main goals for it.&lt;/p&gt;


&lt;h2&gt;
  
  
  Transmission #001: Hello World!
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Where it all starts…
&lt;/h3&gt;

&lt;p&gt;Everything started in the computer room my dad setup when I was just a kid, we had a lot of old computers and gadgets in that room, now that I look back, my dad was kinda of a tech enthusiast himself being a lawyer, I remember a desktop tower running Windows 95, one of those “legendary” &lt;strong&gt;e-machines&lt;/strong&gt; running Windows 98 and that sticker that said “This computer is NEVER OBSOLETE”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Folvuwh6rpjfiwmu90qh8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Folvuwh6rpjfiwmu90qh8.jpg" alt="eMachines computer" width="800" height="1284"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That aged well…&lt;/p&gt;

&lt;p&gt;I spent many hours and days in that room, and even at one point, I made it my own room. That’s where I dabbled in hardware and software for a bit, nothing super crazy, but I was always curious and happy to learn something new.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where I am now…
&lt;/h3&gt;

&lt;p&gt;I’m currently far from the house I grew up in, but I still have that burning passion for technology and learning. I’ve also developed a liking for sharing knowledge via tech talks.&lt;/p&gt;

&lt;p&gt;For the longest time, I wanted to have my own platform for blogging and sharing my thoughts, experiments, and knowledge that others could use or find insightful.&lt;/p&gt;

&lt;p&gt;But I didn’t want just to use Medium or other online platforms; I wanted my own platform, where I set the rules.&lt;/p&gt;

&lt;p&gt;When this thought started, I had little to share on the professional side. I had just started my journey as a Web Developer and didn’t feel ready to “share” whatever little wisdom I had at that moment.&lt;/p&gt;

&lt;p&gt;Now, almost 8 years later, things have changed a lot, and I’ve finally found the right time and the right tools to start this endeavor and go beyond.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where I’m going…
&lt;/h3&gt;

&lt;p&gt;This Tech Blog will be the central place where I share knowledge, tech product experiments, my thoughts, and other things with the world.&lt;/p&gt;

&lt;p&gt;This will be an ever-evolving blog, so don’t expect everything to stay the same or change at all. You might find out I updated an old blog post with new information I came up with, or made a necessary edit due to my own mistake when writing the post, or to the code of an example I created at the time.&lt;/p&gt;

&lt;p&gt;I will also be sharing information about my participation at community-organized and Other Tech Events where I participate as a speaker around Mexico and the World in the near future.&lt;/p&gt;

&lt;p&gt;I’m also working on a No-BS Tech Newsletter. I’m still working around the central concept and the content before launching it or collecting emails, so keep tuned for that in the near future.&lt;/p&gt;

&lt;p&gt;But as of today, December 26h, 2025, I will be posting random one-off blog posts about new techniques and neat things I learn when performing some experiments. I’m also working on publishing a few “100 Days of …” Series for some of the Tools and Technologies I use as a Systems Architect/Platform Engineer in my day-to-day job.&lt;/p&gt;

&lt;p&gt;In the future, I might create some spin-off specialized courses of the tools I’m working with.&lt;/p&gt;

&lt;h3&gt;
  
  
  “Per ardua ad astra”
&lt;/h3&gt;

&lt;p&gt;Nothing has been easy so far, but I’m really motivated for this new start, that’s how I see it, and I’m happy to be able to share this knowledge with everybody.&lt;/p&gt;

&lt;p&gt;I’m especially committed to creating high-quality tech content for the Spanish-speaking community to help everyone in LATAM grow their skills.&lt;/p&gt;

&lt;p&gt;I hope you find my blog useful and you learn something new!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Transmission Ended: Armando Herra @ Dec 26, 2025&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;em&gt;If you enjoy my work, you can support it through &lt;a href="https://github.com/sponsors/ArmandoHerra" rel="noopener noreferrer"&gt;GitHub Sponsors&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Delivered via my personal automated publishing workflow, written with human ideas, words, and work behind.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;More content at blog.armandoherra.com&lt;/em&gt;&lt;/p&gt;

</description>
      <category>blog</category>
      <category>personal</category>
      <category>writing</category>
      <category>devjournal</category>
    </item>
  </channel>
</rss>
