<?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: NeuralAlpha</title>
    <description>The latest articles on DEV Community by NeuralAlpha (@neuralalpha).</description>
    <link>https://dev.to/neuralalpha</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%2F4176323%2Fc7518291-b1e8-489e-a2b9-bea79ba65b04.png</url>
      <title>DEV Community: NeuralAlpha</title>
      <link>https://dev.to/neuralalpha</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/neuralalpha"/>
    <language>en</language>
    <item>
      <title>Your MCP config is now an attack surface: a 20-minute inventory, and the four October incidents behind it</title>
      <dc:creator>NeuralAlpha</dc:creator>
      <pubDate>Tue, 27 Oct 2026 13:49:25 +0000</pubDate>
      <link>https://dev.to/neuralalpha/your-mcp-config-is-now-an-attack-surface-a-20-minute-inventory-and-the-four-october-incidents-4dco</link>
      <guid>https://dev.to/neuralalpha/your-mcp-config-is-now-an-attack-surface-a-20-minute-inventory-and-the-four-october-incidents-4dco</guid>
      <description>&lt;p&gt;For most of this year, "MCP security" meant a hypothetical: what if a tool description tricks the model? October made it concrete. Four incidents in about two weeks all point at the same, unglamorous place: the list of servers and keys your coding tools load when they start.&lt;/p&gt;

&lt;p&gt;I'm not going to tell you to stop using MCP. I use it. What I'd do instead is spend 20 minutes making that list visible, then make it boring to change. Below are the four incidents (only what I could confirm in the source), then the inventory, step by step, with a small script.&lt;/p&gt;

&lt;h2&gt;
  
  
  The four incidents
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. A reverse shell registered as an MCP tool.&lt;/strong&gt; Per CloudSEK's report (October 5, summarized by Platform Engineering on October 19), a ransomware affiliate registered a reverse shell as a tool inside an AI coding assistant through MCP and ran live attack operations through it. More than twenty organizations in six countries were compromised. The same operator scanned the internet for exposed MCP server ports. The article's key line for defenders: there is no CVE to patch here.&lt;/p&gt;

&lt;p&gt;That's the uncomfortable part. Nothing was "broken." A tool was added, and the assistant used it as designed.&lt;/p&gt;

&lt;p&gt;Source: &lt;a href="https://platformengineering.com/features/attackers-have-found-mcp-what-platform-teams-should-do-about-it/" rel="noopener noreferrer"&gt;https://platformengineering.com/features/attackers-have-found-mcp-what-platform-teams-should-do-about-it/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. "Add MCP server" turned out to be a shell prompt.&lt;/strong&gt; Langflow CVE-2026-105740 (CVSS 9.9): any authenticated user, not just an admin, could get code execution on the server by adding an MCP server with the stdio transport. The command went to bash -c without validation. Versions before 1.9.0 are affected. The Hacker News reports honeypots logged over 1,700 exploit attempts. A second bug in the same area, CVE-2026-105697, was patched in 1.10.3.&lt;/p&gt;

&lt;p&gt;Source: &lt;a href="https://thehackernews.com/2026/10/langflows-critical-authenticated-rce.html" rel="noopener noreferrer"&gt;https://thehackernews.com/2026/10/langflows-critical-authenticated-rce.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. An infostealer that now reads AI tool configs.&lt;/strong&gt; Symantec reported on October 15 that the newest version of the Aoki infostealer targets .claude.json, Claude desktop cookies, the Codex config.toml and .env files, plus tokens for GitHub Copilot, Cursor, Gemini, JetBrains AI Assistant and Kiro, and AWS credentials. Older samples didn't look for AI-related files at all. The AI targeting is new.&lt;/p&gt;

&lt;p&gt;Source: &lt;a href="https://www.security.com/threat-intelligence/aoki-infostealer-ai-targeting" rel="noopener noreferrer"&gt;https://www.security.com/threat-intelligence/aoki-infostealer-ai-targeting&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Keys stored in someone else's dashboard.&lt;/strong&gt; The Hacker News reported on October 19 that a breach of a legacy OpenCode Console system may have exposed provider API keys for about 1.4% of Console users. No MCP involved, but the same lesson: a key you paste into a third-party service leaks on their schedule, not yours.&lt;/p&gt;

&lt;p&gt;Source: &lt;a href="https://thehackernews.com/2026/10/opencode-console-breach-may-have.html" rel="noopener noreferrer"&gt;https://thehackernews.com/2026/10/opencode-console-breach-may-have.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Put together: the config files that list your MCP servers, and the keys sitting next to them, are now worth stealing and worth tampering with. So the first job is knowing what's in them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 20-minute inventory
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1 (5 min): find every file that can start a server
&lt;/h3&gt;

&lt;p&gt;On a typical solo setup, MCP servers can be defined in several places at once:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;~/.claude.json (Claude Code, user-level and per-project mcpServers)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;.mcp.json in a repo (Claude Code, project-scoped, and it travels with the repo)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;~/.cursor/mcp.json (Cursor)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;~/.codex/config.toml (Codex CLI, [mcp_servers.*] tables)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;claude_desktop_config.json (Claude Desktop)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The .mcp.json in a repo is the one people forget. If you clone a project that ships one, its servers are on your list too, subject to whatever approval prompt your tool shows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2 (5 min): write down each server, its owner and what it can reach
&lt;/h3&gt;

&lt;p&gt;For every server, one line: name, command or URL, who maintains it, and what it can touch (files, network, which credentials in its env). If you can't name the maintainer, that's a finding. If its env block holds a long-lived token with write scope, that's a finding.&lt;/p&gt;

&lt;p&gt;Here is the script I use for the listing. Standard library only. It prints server names and commands, never env values or file contents, and it stores SHA-256 hashes so the next run tells you which files changed.&lt;/p&gt;

&lt;h1&gt;
  
  
  !/usr/bin/env python3
&lt;/h1&gt;

&lt;p&gt;"""List MCP servers your coding tools will start; notice when key files change.&lt;br&gt;
  python3 mcp_inventory.py          # print inventory, compare with baseline&lt;br&gt;
  python3 mcp_inventory.py --save   # store current hashes as the baseline&lt;br&gt;
"""&lt;br&gt;
import hashlib, json, pathlib, sys&lt;/p&gt;

&lt;p&gt;HOME = pathlib.Path.home()&lt;br&gt;
CANDIDATES = [&lt;br&gt;
    HOME / ".claude.json",&lt;br&gt;
    pathlib.Path.cwd() / ".mcp.json",&lt;br&gt;
    HOME / ".cursor" / "mcp.json",&lt;br&gt;
    HOME / ".codex" / "config.toml",&lt;br&gt;
    HOME / "Library/Application Support/Claude/claude_desktop_config.json",&lt;br&gt;
    HOME / "AppData/Roaming/Claude/claude_desktop_config.json",&lt;br&gt;
    pathlib.Path.cwd() / ".env",&lt;br&gt;
]&lt;br&gt;
BASELINE = HOME / ".mcp_inventory_baseline.json"&lt;/p&gt;

&lt;p&gt;def servers_in(p):&lt;br&gt;
    if p.suffix == ".toml":&lt;br&gt;
        for line in p.read_text(encoding="utf-8", errors="replace").splitlines():&lt;br&gt;
            s = line.strip()&lt;br&gt;
            if s.startswith("[mcp_servers.") and s.endswith("]"):&lt;br&gt;
                yield ("codex", s[len("[mcp_servers."):-1], "?")&lt;br&gt;
        return&lt;br&gt;
    if p.suffix != ".json":&lt;br&gt;
        return&lt;br&gt;
    try:&lt;br&gt;
        data = json.loads(p.read_text(encoding="utf-8"))&lt;br&gt;
    except (ValueError, UnicodeDecodeError):&lt;br&gt;
        yield ("?", "(unreadable JSON)", ""); return&lt;br&gt;
    blocks = [("user", data.get("mcpServers") or {})]&lt;br&gt;
    for proj, cfg in (data.get("projects") or {}).items():&lt;br&gt;
        if isinstance(cfg, dict):&lt;br&gt;
            blocks.append((proj, cfg.get("mcpServers") or {}))&lt;br&gt;
    for scope, block in blocks:&lt;br&gt;
        for name, cfg in block.items():&lt;br&gt;
            cfg = cfg if isinstance(cfg, dict) else {}&lt;br&gt;
            cmd = cfg.get("command") or cfg.get("url") or cfg.get("type") or "?"&lt;br&gt;
            args = [str(a) for a in cfg.get("args", [])]&lt;br&gt;
            yield (scope, name, " ".join([str(cmd)] + args)[:120])&lt;/p&gt;

&lt;p&gt;old = json.loads(BASELINE.read_text()) if BASELINE.exists() else {}&lt;br&gt;
now = {}&lt;br&gt;
for p in CANDIDATES:&lt;br&gt;
    if not p.is_file():&lt;br&gt;
        continue&lt;br&gt;
    h = hashlib.sha256(p.read_bytes()).hexdigest()&lt;br&gt;
    now[str(p)] = h&lt;br&gt;
    flag = "" if not old else ("  [same]" if old.get(str(p)) == h else "  [CHANGED or new]")&lt;br&gt;
    print(f"{p}{flag}")&lt;br&gt;
    for scope, name, cmd in servers_in(p):&lt;br&gt;
        print(f"    {scope:&amp;lt;12} {name:&amp;lt;24} {cmd}")&lt;br&gt;
for gone in sorted(set(old) - set(now)):&lt;br&gt;
    print(f"{gone}  [missing since baseline]")&lt;br&gt;
if "--save" in sys.argv:&lt;br&gt;
    BASELINE.write_text(json.dumps(now, indent=2))&lt;br&gt;
    print(f"baseline saved: {BASELINE}")&lt;br&gt;
elif not old:&lt;br&gt;
    print("no baseline yet: run again with --save")One honest caveat: ~/.claude.json changes often on its own, because Claude Code writes session state into it. A [CHANGED] flag on that file is normal. What matters is whether the server list under it changed. The hash is more useful for .mcp.json, mcp.json, config.toml and .env, which shouldn't move unless you moved them.&lt;/p&gt;

&lt;p&gt;I tested it against a throwaway home directory with fake configs before publishing: it listed all four servers, flagged only the file I edited after --save, and never printed the dummy token sitting in an env block.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3 (5 min): cut
&lt;/h3&gt;

&lt;p&gt;For each server, ask: did I use this in the last two weeks? If not, remove it. A server you forgot about still starts with your agent and your credentials. Then, for the ones you keep:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Disable tools you don't use (many servers ship with write tools on by default).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Move long-lived tokens out of env blocks in shared files. At minimum, never commit them in a repo's .mcp.json.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Anything listening on a network port: bind to localhost or put it behind auth. The CloudSEK operator was scanning for exposed MCP ports.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 4 (5 min): make leaks cheap
&lt;/h3&gt;

&lt;p&gt;You can't fully prevent key theft on a laptop that runs an infostealer. You can make a stolen key boring:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;One key per tool.&lt;/strong&gt; If your coding agent, your MCP GitHub server and your CI share one token, one leak means rotating everything and guessing what was used where.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A spend cap set at the provider, not in your code.&lt;/strong&gt; Code-side limits don't help when the key is used from someone else's machine.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Write down the revoke steps&lt;/strong&gt; for each key now, while you're calm: which console, which page.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What this looks like in my own setup
&lt;/h2&gt;

&lt;p&gt;I run a small, mostly unattended publishing stack (scheduled jobs that post through the X API and record results). It's not an enterprise environment, but the same rules apply:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The X API key sits in a .env outside any repo, and the billing cycle cap is set in the X developer console ($5), with auto-recharge off. If the key leaked, the damage is bounded by that cap, not by my code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The posting script checks which account it is authenticated as before every post and stops if it's not the expected one.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It writes attempt to a ledger before sending and sent after. So far that ledger shows 29 attempts and 29 sends, no unknowns, no duplicates.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And one thing I haven't fixed yet: the hooks in my own Claude Code guardrails plugin still don't set onFailure, so if Python is missing the guard is skipped rather than blocking. I wrote about that last week. It's still on the list. Inventories are useful partly because they show you your own gaps.&lt;/p&gt;

&lt;h2&gt;
  
  
  The checklist, short version
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;List every file that can define an MCP server (including repo .mcp.json).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;One line per server: command, maintainer, what it can reach, which credentials.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hash the config and .env files; re-run weekly and read what changed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Remove anything unused for two weeks; disable unused tools.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No secrets in committed MCP configs; nothing listening on a public port.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;One key per tool, provider-side spend caps, revoke steps written down.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want this as a printable one-pager with the rest of the pre-flight checks I run before letting an agent act on its own, the free checklist is here: &lt;a href="https://neuralalpha.gumroad.com/l/agent-ops-preflight?utm_source=substack&amp;amp;utm_medium=article" rel="noopener noreferrer"&gt;https://neuralalpha.gumroad.com/l/agent-ops-preflight?utm_source=substack&amp;amp;utm_medium=article&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://neuralalphaai.substack.com/p/your-mcp-config-is-now-an-attack" rel="noopener noreferrer"&gt;NeuralAlpha&lt;/a&gt;. I write weekly about running AI agents in production.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>automation</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Five agent failures from the last two weeks, and the check that stops each one</title>
      <dc:creator>NeuralAlpha</dc:creator>
      <pubDate>Tue, 20 Oct 2026 13:49:20 +0000</pubDate>
      <link>https://dev.to/neuralalpha/five-agent-failures-from-the-last-two-weeks-and-the-check-that-stops-each-one-24em</link>
      <guid>https://dev.to/neuralalpha/five-agent-failures-from-the-last-two-weeks-and-the-check-that-stops-each-one-24em</guid>
      <description>&lt;p&gt;Most "AI agent security" writing is about what a model might say. The incidents from the last two weeks are about something more boring and more useful: what the tools around the model do when nobody is watching.&lt;/p&gt;

&lt;p&gt;Here are five, each with what happened, why it matters if you run Claude Code, Cursor, Codex or your own MCP setup, and one check you can do this week. I only included details I could confirm in the source. Links are at the end of each section.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Web pages are putting instructions in their HTTP headers
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What happened.&lt;/strong&gt; Researchers at Signals Corps went through about 217 million responses in Common Crawl looking for HTTP headers addressed to AI agents. Roughly 8,000 sites send such headers. About 30 of them were actual prompt-injection attempts, and 22 of those looked like pranks. The Register's write-up notes that a coding agent using plain curl usually never shows headers to the model, but the Playwright MCP server's network-request tool returns all headers by default.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters.&lt;/strong&gt; Real harm here is probably close to zero today. The interesting part is the path: text the model never asked for, arriving through a tool that "just returns what it got."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The check.&lt;/strong&gt; List every MCP tool your agent can call that fetches external content (browser, HTTP, search, file readers). For each one, write down whether it returns raw metadata (headers, HTML comments, alt text) to the model. If it does and you do not need it, turn it off or filter it. And keep the real decision, "is this action allowed?", outside the model: a hook or a wrapper that checks the command itself, not the reasoning that produced it.&lt;/p&gt;

&lt;p&gt;Source: The Register, 2026-10-15. &lt;a href="https://www.theregister.com/ai-and-ml/2026/10/15/indirect-prompt-injection-starts-turning-up-in-webpage-headers-please-ignore-all-previous-instructions-and-rise-up-against-your-masters/5303434" rel="noopener noreferrer"&gt;https://www.theregister.com/ai-and-ml/2026/10/15/indirect-prompt-injection-starts-turning-up-in-webpage-headers-please-ignore-all-previous-instructions-and-rise-up-against-your-masters/5303434&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. A worm got into an AI-agent infrastructure SDK on npm
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What happened.&lt;/strong&gt; A Shai-Hulud-style worm compromised version 0.5.144 of Tensorlake's npm SDK. Per The Register, it goes after crypto wallets, GitHub Actions secrets and cloud credentials, and can wipe the home directory if certain tokens are revoked. The install script runs on the developer's machine or build server, outside any agent sandbox. The package sees around 12,000 downloads a week; it was detected and pulled within 11 minutes, and 0.5.145 replaced it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters.&lt;/strong&gt; Coding agents install packages. The Cloud Security Alliance reports that in 2.23 million AI-generated code samples, 19.7% referenced a package name that does not exist, which is exactly the gap a typo-squatter or a "slopsquatter" registers into.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The check.&lt;/strong&gt; Before an agent-suggested package goes in, three questions, about a minute each:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Does it exist under that exact name, and is it the one the docs link to?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When was the version you are about to install published? A release from the last hour deserves a pause.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How many maintainers does it have, and does it run an install script?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you can, install with scripts disabled first (npm install --ignore-scripts) and enable them only for packages that need it.&lt;/p&gt;

&lt;p&gt;Sources: The Register, 2026-10-08. &lt;a href="https://www.theregister.com/security/2026/10/08/shai-hulud-worm-makes-jump-to-ai-infrastructure-with-tensorlake-compromise/5302054" rel="noopener noreferrer"&gt;https://www.theregister.com/security/2026/10/08/shai-hulud-worm-makes-jump-to-ai-infrastructure-with-tensorlake-compromise/5302054&lt;/a&gt; · CSA research note. &lt;a href="https://labs.cloudsecurityalliance.org/research/csa-research-note-ai-agents-software-supply-chain-risk-20260/" rel="noopener noreferrer"&gt;https://labs.cloudsecurityalliance.org/research/csa-research-note-ai-agents-software-supply-chain-risk-20260/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The MCP Python SDK could hand OAuth secrets to a malicious server
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What happened.&lt;/strong&gt; Advisory WS-2026-0089: the MCP Python SDK's OAuth client did not validate the authorization server's issuer on every path and did not bind stored credentials to the server that issued them. A malicious or compromised MCP server could point the client at its own token endpoint and collect the client secret, the authorization code and the PKCE verifier. CVSS v4 8.7. Affected: 1.9.1 through 1.29.1 and 2.0.0a1 through 2.1.1. Fixed in 1.30.0 and 2.2.0.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters.&lt;/strong&gt; "I only connect to MCP servers I trust" is not a complete defense when one trusted server can redirect your credentials somewhere else.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The check.&lt;/strong&gt; Run pip show mcp in every environment that hosts an MCP client, including CI images and that old virtualenv on the build box. Anything below 1.30.0 (or a 2.x below 2.2.0) gets upgraded. Then rotate any client secret that was ever used with a server you would not stake your account on.&lt;/p&gt;

&lt;p&gt;Source: Mend vulnerability database, updated 2026-10-07. &lt;a href="https://www.mend.io/vulnerability-database/WS-2026-0089/" rel="noopener noreferrer"&gt;https://www.mend.io/vulnerability-database/WS-2026-0089/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. An Odoo MCP server let the agent read fields it was not allowed to see
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What happened.&lt;/strong&gt; CVE-2026-108861: in erpipe-org/mcp-odoo versions 1.0.0 to 1.3.2, calling the execute_method tool skipped field-level access control, so values from denied fields could be read. CVSS 4.3, published 2026-10-11. The source I read did not list a fixed version.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters.&lt;/strong&gt; Low severity, but a common shape: an MCP server exposes one "generic" tool that calls anything, and the generic path forgets the rules the specific paths enforce.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The check.&lt;/strong&gt; For each MCP server, read its tool list and flag anything named like execute, run, call_method, query or raw. Ask whether the agent needs it. If it does not, deny that tool in your client's permission settings even if you keep the server.&lt;/p&gt;

&lt;p&gt;Source: &lt;a href="https://www.thehackerwire.com/vulnerability/CVE-2026-108861/" rel="noopener noreferrer"&gt;https://www.thehackerwire.com/vulnerability/CVE-2026-108861/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Hooks that crash let the action through
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What happened.&lt;/strong&gt; Claude Code's changelog for v2.1.295 (October 8) adds onFailure: "block" for command and HTTP hooks: if the hook cannot start, times out or exits abnormally, the action is stopped instead of allowed. The release before it, v2.1.294, fixed a bug where prompt- or agent-based hooks written as instructions ("block commands that...") could sometimes let the operation through.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters.&lt;/strong&gt; A guard that silently disappears when it breaks is worse than no guard, because you stop looking. "Fail open" is a reasonable default for a developer convenience. It is the wrong default for the hook that stops rm -rf or a production deploy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The check, and an honest note from my side.&lt;/strong&gt; I looked at my own open-source plugin's hooks.json today. It sets a 10-second timeout on the guard script and does not set onFailure yet. So if Python is missing on a machine, the guard is skipped. That goes on my list for the next version. For yours:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Open your hook config and find every hook that is supposed to stop something.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Break it on purpose: rename the script it calls, then ask the agent to do the thing the hook should block.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the action goes through, add "onFailure": "block" to that hook (on a current Claude Code version) and run the test again.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It takes about three minutes and tells you more than reading the config ever will.&lt;/p&gt;

&lt;p&gt;Source: &lt;a href="https://github.com/anthropics/claude-code/releases" rel="noopener noreferrer"&gt;https://github.com/anthropics/claude-code/releases&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern
&lt;/h2&gt;

&lt;p&gt;None of these needed a clever model attack. They are a tool returning too much, a package nobody checked, a credential not tied to its issuer, a generic method skipping rules, and a guard that vanishes when it breaks.&lt;/p&gt;

&lt;p&gt;The same rule covers all five: &lt;strong&gt;put the decision outside the model, and make it fail closed.&lt;/strong&gt; My own unattended posting script follows a small version of this. It writes an attempt row to its ledger before every API call, and if any earlier row ends in unknown, it refuses to post until a human looks. It is slower. It has never double-posted.&lt;/p&gt;

&lt;h2&gt;
  
  
  A one-page version
&lt;/h2&gt;

&lt;p&gt;The broader list I run before letting an agent act on its own (identity checks, arming, the write ledger, hard limits, deliverable checks) is a free one-page PDF (Gumroad asks for an email to deliver it):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://neuralalpha.gumroad.com/l/agent-ops-preflight?utm_source=substack&amp;amp;utm_medium=article" rel="noopener noreferrer"&gt;https://neuralalpha.gumroad.com/l/agent-ops-preflight?utm_source=substack&amp;amp;utm_medium=article&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you ran the "break your hook on purpose" test, I would like to know what happened. Reply to this email or leave a comment.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://neuralalphaai.substack.com/p/five-agent-failures-from-the-last" rel="noopener noreferrer"&gt;NeuralAlpha&lt;/a&gt;. I write weekly about running AI agents in production.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>automation</category>
      <category>productivity</category>
    </item>
    <item>
      <title>5 falhas que só aparecem quando seu agente de IA roda sozinho (e uma checagem de 3 minutos para cada)</title>
      <dc:creator>NeuralAlpha</dc:creator>
      <pubDate>Mon, 19 Oct 2026 22:50:15 +0000</pubDate>
      <link>https://dev.to/neuralalpha/5-falhas-que-so-aparecem-quando-seu-agente-de-ia-roda-sozinho-e-uma-checagem-de-3-minutos-para-2m7</link>
      <guid>https://dev.to/neuralalpha/5-falhas-que-so-aparecem-quando-seu-agente-de-ia-roda-sozinho-e-uma-checagem-de-3-minutos-para-2m7</guid>
      <description>&lt;p&gt;Quando a gente cria um agente de IA ou um job agendado, o primeiro alívio vem quando "funcionou": o post saiu, o arquivo foi gerado, o job terminou.&lt;/p&gt;

&lt;p&gt;Só que, quando ele começa a rodar sem ninguém olhando, aparece outro tipo de falha. Publicar a mesma coisa duas vezes. Quase escrever na conta errada. Parar sem que ninguém perceba. Entregar ao cliente um arquivo que não deveria estar ali. Funcionar de dia e cair só de madrugada.&lt;/p&gt;

&lt;p&gt;Eu rodo uma operação pequena de automação (posts automáticos, distribuição de produtos digitais, jobs noturnos em Python e Claude Code). As cinco falhas abaixo aconteceram comigo, ou quase aconteceram. Não tem exemplo inventado. Para cada uma deixei uma checagem que leva uns 3 minutos.&lt;/p&gt;

&lt;p&gt;A ideia que atravessa tudo: &lt;strong&gt;coloque o freio no programa, não no prompt.&lt;/strong&gt; Em vez de pedir para a IA "não enviar duas vezes", o código confere o registro antes de enviar e, se já existe, não envia.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Envio duplicado: a mesma escrita acontece duas vezes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;O que acontece.&lt;/strong&gt; O post ou o envio sai duas vezes. Em rede social isso derruba a confiança da conta; em e-mail ou pagamento, causa dano real a outra pessoa.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Por que acontece.&lt;/strong&gt; O caso clássico é "não sei se enviou". A requisição deu timeout, ou o processo caiu antes da resposta. Do outro lado já tinha sido processado, mas o seu código entende como falha e tenta de novo. Agentes de IA tendem a dizer "falhou, vou tentar de novo" com toda a boa vontade, então esse padrão aparece fácil.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Checagem de 3 minutos&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Você grava "vou enviar isto" &lt;strong&gt;antes&lt;/strong&gt; de enviar? Se só grava depois, uma queda no meio não deixa rastro.&lt;/li&gt;
&lt;li&gt;Quando o resultado é desconhecido (timeout etc.), o job tenta de novo sozinho? O mais seguro é marcar como "desconhecido", parar, e uma pessoa confirmar antes de seguir.&lt;/li&gt;
&lt;li&gt;Se o mesmo conteúdo for enviado de novo, existe algo que olha o registro e bloqueia?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Escrever na conta errada
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;O que acontece.&lt;/strong&gt; Quem tem várias contas ou projetos acaba escrevendo no lugar errado: trabalho e pessoal, produção e teste.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Por que acontece.&lt;/strong&gt; O token vem de variável de ambiente ou arquivo de configuração. Se você troca o arquivo ou esquece de mudar, o programa segue em silêncio. Eu tenho duas contas na mesma rede social e uma delas nunca pode publicar nada desta operação; por isso o job confere a identidade antes de cada envio.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Checagem de 3 minutos&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Logo antes de escrever, o job pergunta para a API "quem sou eu?" e para se o ID não for o esperado?&lt;/li&gt;
&lt;li&gt;O ID esperado fica num lugar diferente do token (no código ou numa configuração fixa)? Se os dois ficam no mesmo arquivo, eles se trocam juntos.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Parada silenciosa: parou e ninguém percebeu
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;O que acontece.&lt;/strong&gt; O job agendado não rodou, e não apareceu erro nem aviso. Quando você nota, faltam dias de processamento.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Por que acontece.&lt;/strong&gt; Se o job quebra, dá para avisar. Mas um job que nem iniciou não gera erro. No meu caso, a atualização automática do Windows reiniciou o PC de madrugada e as tarefas daquela noite simplesmente não rodaram. Saldo de API acabando também é uma forma de parada silenciosa.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Checagem de 3 minutos&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Além de "registrar quando roda", existe "avisar se ficou X horas sem registro" (monitoramento de vida)?&lt;/li&gt;
&lt;li&gt;Existe aviso antes de acabar o saldo ou a cota de uma API paga?&lt;/li&gt;
&lt;li&gt;Se roda no seu PC, você conferiu o horário de reinício automático e a configuração de suspensão?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Arquivo que não deveria estar no entregável
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;O que acontece.&lt;/strong&gt; O ZIP ou PDF que você vende ou distribui leva junto notas internas, rascunhos, arquivos de configuração. No pior caso, segredos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Por que acontece.&lt;/strong&gt; Compactar a pasta de trabalho inteira leva junto o que está em andamento. Eu fiz uma compra de teste de um kit que já estava à venda e, ao abrir o ZIP recebido, descobri que cerca de metade do conteúdo era material interno do vendedor. Troquei na hora por uma versão só com os arquivos do comprador.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Checagem de 3 minutos&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O entregável é montado a partir de uma &lt;strong&gt;lista do que pode entrar&lt;/strong&gt;, e não da pasta inteira?&lt;/li&gt;
&lt;li&gt;Você recebeu o arquivo pelo mesmo caminho do cliente e conferiu (por hash, por exemplo) se é idêntico ao que gerou?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Cai só de madrugada: na mão funciona, no agendador quebra
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;O que acontece.&lt;/strong&gt; Rodando você mesmo, tudo certo. Rodando pelo Agendador de Tarefas ou cron de madrugada, falha.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Por que acontece.&lt;/strong&gt; Pelo agendador mudam a pasta de trabalho, as variáveis de ambiente, a codificação de texto e o usuário logado. No Windows japonês, por exemplo, a saída padrão usa cp932 e o script cai no instante em que tenta imprimir um caractere fora dessa codificação. Foi exatamente o que aconteceu num job meu.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Checagem de 3 minutos&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O script define explicitamente a pasta de trabalho e a codificação (por exemplo &lt;code&gt;PYTHONUTF8=1&lt;/code&gt;)?&lt;/li&gt;
&lt;li&gt;Você já disparou o job pelo agendador, de dia, e leu o log?&lt;/li&gt;
&lt;li&gt;Você sabe onde fica o log quando ele cai?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Bônus: limite antes de aumentar o volume
&lt;/h2&gt;

&lt;p&gt;Quando a automação funciona, dá vontade de aumentar a frequência. Só que, quanto mais vezes ela roda, maior o estrago quando uma das cinco falhas acontece. E posts parecidos em intervalos curtos podem ser vistos pela plataforma como abuso de automação; isso aconteceu com a minha conta (o rótulo foi removido depois da revisão).&lt;/p&gt;

&lt;p&gt;Defina &lt;strong&gt;no código&lt;/strong&gt; um limite por dia e um intervalo mínimo, e tenha um interruptor que pare tudo de uma vez quando algo parecer errado.&lt;/p&gt;

&lt;h2&gt;
  
  
  Para levar
&lt;/h2&gt;

&lt;p&gt;Nenhuma dessas falhas some quando a IA fica mais inteligente. Não saber se enviou, não saber com qual conta está logado, não saber que parou: tudo isso se resolve fazendo o sistema &lt;strong&gt;parar quando não sabe&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Se quiser uma versão para imprimir, fiz um &lt;strong&gt;checklist gratuito em português&lt;/strong&gt; (PDF de uma página, 25 verificações): &lt;a href="https://neuralalpha.gumroad.com/l/agent-ops-preflight-pt-br?utm_source=devto&amp;amp;utm_medium=article_ptbr" rel="noopener noreferrer"&gt;Checklist pré-voo de Agent Ops&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;E se quiser a implementação completa em Python (só biblioteca padrão, 10 capítulos: registro antes do envio, "quem sou eu", monitoramento de vida e de custo, inspeção do entregável, jobs noturnos), o guia está em português: &lt;a href="https://neuralalpha.gumroad.com/l/agent-ops-guide-pt-br?utm_source=devto&amp;amp;utm_medium=article_ptbr" rel="noopener noreferrer"&gt;Antes de deixar agentes de IA escreverem sem supervisão&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Se você já passou por alguma falha diferente dessas, conta nos comentários. Quero incluir na próxima revisão.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;A tradução para o português teve auxílio de IA; os casos são da minha própria operação.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>automation</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Treat a 200 as a claim: the four-row ledger that stops my bot from double-posting</title>
      <dc:creator>NeuralAlpha</dc:creator>
      <pubDate>Tue, 13 Oct 2026 13:48:28 +0000</pubDate>
      <link>https://dev.to/neuralalpha/treat-a-200-as-a-claim-the-four-row-ledger-that-stops-my-bot-from-double-posting-2fml</link>
      <guid>https://dev.to/neuralalpha/treat-a-200-as-a-claim-the-four-row-ledger-that-stops-my-bot-from-double-posting-2fml</guid>
      <description>&lt;p&gt;Most automation failures I worry about are not crashes. A crash is loud. The ones that cost money are quiet duplicates: the same email sent twice, the same order placed twice, the same post published twice because a request timed out and something helpfully tried again.&lt;/p&gt;

&lt;p&gt;My setup is small. A scheduled script posts to X through the official API, up to five times a day. It runs while I sleep. So the question I designed it around was not "how do I make it post?" but "what happens when it is not sure whether it posted?"&lt;/p&gt;

&lt;p&gt;The answer is a ledger with four possible states, and one rule: &lt;strong&gt;the ledger is written before the network call, not after.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with "it returned 200"
&lt;/h2&gt;

&lt;p&gt;When you call an API to do something (send, create, charge), there are three outcomes, not two:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It worked, and you got a response saying so.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It failed, and you got a response saying so.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You don't know. The connection dropped, the request timed out, the process was killed, the machine went to sleep.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most code treats case 3 as case 2. It catches the exception and retries. That is exactly how duplicates happen: the first request did go through, the response just never came back.&lt;/p&gt;

&lt;p&gt;The reverse mistake is also common. A 200 means the server &lt;em&gt;accepted&lt;/em&gt; something. It does not always mean the thing you care about happened the way you think. That is why I say "treat a 200 as a claim, not a confirmation." Where it matters, read the object back.&lt;/p&gt;

&lt;h2&gt;
  
  
  The four rows
&lt;/h2&gt;

&lt;p&gt;Every time my script decides to post, it appends rows to a plain JSONL file. One line per event:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;attempt: written &lt;em&gt;before&lt;/em&gt; the API call. It records the queue item ID, the date, the account, and a SHA-256 of the exact text.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;sent: written after a successful response, with the returned post ID and URL.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;failed: written when the API returns an error response, with the HTTP code and the first part of the body.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;unknown: written when anything else goes wrong mid-send, such as a timeout or a dropped connection.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last row for a given item is its final state. If the process dies between attempt and anything else, the file still says attempt, and that is treated the same as unknown.&lt;/p&gt;

&lt;p&gt;The order matters more than the format. If you write the log entry after the call, a crash in between leaves no trace that you ever tried. Writing it first means the worst case is "we tried and don't know the result," which is recoverable by a human. The other worst case, "we tried, it worked, and we have no record," is how you get a second copy at 3 a.m.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rule that makes it work: unknown blocks the queue
&lt;/h2&gt;

&lt;p&gt;Before every run, the script reads the whole ledger. If any item's final state is attempt or unknown, it prints a STOP message and exits without posting anything.&lt;/p&gt;

&lt;p&gt;It does not retry. It does not skip to the next item. It waits for me.&lt;/p&gt;

&lt;p&gt;That sounds inconvenient, and it is, a little. In practice, it is the cheapest decision in the whole system. Checking whether one post went out takes me under a minute. Cleaning up a duplicate, on a platform that penalizes duplicate content, takes longer and looks worse.&lt;/p&gt;

&lt;p&gt;So far the ledger has recorded every post as attempt followed by sent. It has never double-posted. It also cannot recover from an unknown on its own. Both of those are by design.&lt;/p&gt;

&lt;h2&gt;
  
  
  The other checks that run before the call
&lt;/h2&gt;

&lt;p&gt;The ledger is the core, but it sits inside a short list of checks. They run in this order, and any one of them can stop the run:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Daily cap.&lt;/strong&gt; At most five write attempts per day (Japan time). Attempts count, not just successes, so a failing run cannot burn through the cap by retrying.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Minimum gap.&lt;/strong&gt; At least 50 minutes since the last attempt.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No unresolved attempt.&lt;/strong&gt; The rule above.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Approved only.&lt;/strong&gt; The script only posts items marked approved in the queue, whose date is today or earlier.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No surprise links.&lt;/strong&gt; If the text contains a URL and the item was not explicitly allowed to have one, it stops. Link posts cost more, and a stray URL is also a common sign that the wrong text got into the queue.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Length.&lt;/strong&gt; It computes X's weighted length itself and stops above 280, instead of letting the API reject it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No identical text.&lt;/strong&gt; If a post with the same SHA-256 was already sent, it stops.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Identity.&lt;/strong&gt; Before the first write of the day, it asks the API which account the token belongs to and compares it to one hard-coded handle. I run more than one account on the same machine. A mismatch stops everything. The result is cached for the day, so this costs one read per day, not one per post.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Only after all of that does it write the attempt row and make the call.&lt;/p&gt;

&lt;p&gt;There is also a --dry-run flag that runs every check, prints the next post, and makes no network calls and no file changes. My weekly job uses it to confirm the queue is valid before I walk away.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this looks like for emails, orders and payments
&lt;/h2&gt;

&lt;p&gt;I use this for social posts because that is what I run. The same shape applies anywhere a retry could create a second real-world effect. If you send emails from a job, place orders through an API, or move money:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Give every action an ID before you act.&lt;/strong&gt; Generate it when you decide to do the thing, not when you do it. If the provider supports idempotency keys, send that ID as the key, so a retried request is recognized as the same request.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Write "attempt" before the call.&lt;/strong&gt; Same reason as above.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Separate "failed" from "unknown."&lt;/strong&gt; An error response is information. A timeout is the absence of information. Only the first is safe to retry automatically, and even then only if the provider tells you nothing happened.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Make unknown stop the line.&lt;/strong&gt; Not forever. Until a person, or a read-back check, resolves it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Read the object back when it matters.&lt;/strong&gt; If a payment API returns success, look up the payment. If an email API returns accepted, check the provider's log. A 200 is a claim.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A checklist you can run against your own job
&lt;/h2&gt;

&lt;p&gt;If you have one scheduled job that writes to the outside world, go through this in ten minutes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;☐ Is there a record of each write attempt that exists &lt;em&gt;before&lt;/em&gt; the network call?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;☐ Does the record distinguish failed from unknown?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;☐ Does an unknown result stop further writes until resolved?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;☐ Do retries reuse the same ID, or generate a new one? (New ID = possible duplicate.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;☐ Is there a cap on attempts, not just on successes?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;☐ Does the job check &lt;em&gt;which account&lt;/em&gt; it is about to act as?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;☐ Is there a dry-run mode that makes no changes at all?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;☐ When the job stops itself, does a person find out?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If any answer is "no," that is the next thing to fix. None of these require a framework. Mine is a single Python file and a text file that only ever gets appended to.&lt;/p&gt;

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

&lt;p&gt;Everything above is old advice from payments and distributed systems. It matters more now because AI agents make a lot of API calls, and their default response to an error is to try again, slightly differently. An agent that is told "the request timed out" will often just resend. If the tool it is calling has side effects, the ledger and the unknown rule need to live in the tool, not in the prompt. You cannot instruct your way out of a duplicate charge.&lt;/p&gt;

&lt;p&gt;If you want the broader list I run before letting any agent or bot act unattended, it is a free one-page checklist: &lt;a href="https://neuralalpha.gumroad.com/l/agent-ops-preflight?utm_source=devto&amp;amp;utm_medium=article" rel="noopener noreferrer"&gt;Agent Ops Pre-Flight Checklist&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I write here weekly about running AI agents and automations in production: what broke, what I check now, and what it cost. Not financial, legal or security advice. Adapt everything to your own systems.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://neuralalphaai.substack.com/p/treat-a-200-as-a-claim-the-four-row" rel="noopener noreferrer"&gt;NeuralAlpha&lt;/a&gt;. I write weekly about running AI agents in production.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>automation</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Seven checks before I let an agent act on its own</title>
      <dc:creator>NeuralAlpha</dc:creator>
      <pubDate>Sun, 11 Oct 2026 05:02:28 +0000</pubDate>
      <link>https://dev.to/neuralalpha/seven-checks-before-i-let-an-agent-act-on-its-own-oe3</link>
      <guid>https://dev.to/neuralalpha/seven-checks-before-i-let-an-agent-act-on-its-own-oe3</guid>
      <description>&lt;p&gt;I run a small, mostly automated publishing setup: a scheduled job writes to X through the official API, digital products sit on Gumroad, and a few overnight scripts keep the books. None of it is big. All of it can embarrass me, or cost me money, while I am asleep.&lt;/p&gt;

&lt;p&gt;This is the list I now run before any agent, bot or scheduled pipeline is allowed to act without me watching. Every item is here because of something that actually happened. No hypotheticals, no invented incidents.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. It checks who it is before the first write
&lt;/h2&gt;

&lt;p&gt;I have more than one account logged in on the same machine. So the posting script asks the API "who am I?" before every send and compares the answer with one hard-coded handle. If they differ, it stops. It does not warn and continue.&lt;/p&gt;

&lt;p&gt;This costs one extra API read per day (I cache it). It is the cheapest insurance in the whole setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Old pipelines are assumed armed until proven otherwise
&lt;/h2&gt;

&lt;p&gt;When I rebuilt the setup, I found an older pipeline that was still configured to post for real. It had not posted only because its quality filter happened to reject everything. That was luck, not a safety design.&lt;/p&gt;

&lt;p&gt;Now "off" means a visible change: a removed flag, a dated backup of the old file, and a note in the ledger saying what was disarmed and when.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. An unknown result blocks the next send
&lt;/h2&gt;

&lt;p&gt;Every write records an "attempt" before it goes out and a result after: sent, failed or unknown. A timeout is "unknown", and unknown blocks the queue until a human looks. There is no automatic retry, because a retried post, email or payment is a duplicate.&lt;/p&gt;

&lt;p&gt;This is the same idea as the line I keep repeating: &lt;strong&gt;treat a 200 as a claim, not a confirmation.&lt;/strong&gt; Where it matters, read the object back.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. The spend cap lives at the provider
&lt;/h2&gt;

&lt;p&gt;My scripts have a daily cap of five posts and log the cost of every call. But the cap I actually trust is the one set in the provider's console, because code caps fail exactly when the code is wrong. The script also estimates the remaining balance and warns me about a week before it runs out, not after.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. I bought my own product and opened the file
&lt;/h2&gt;

&lt;p&gt;This one stung. I did a test purchase of one of my own digital products and opened the ZIP the way a buyer would. About half of it was my internal material: launch plans and notes that never belonged in a customer download.&lt;/p&gt;

&lt;p&gt;The fix was a clean build containing only buyer-facing files, then another test purchase to confirm what arrives. Builds are now reproducible, so the same inputs always give the same SHA-256 and I can say exactly which file a buyer received.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. It ran once under the real scheduler, at night
&lt;/h2&gt;

&lt;p&gt;An unattended job died overnight with a UnicodeEncodeError. The Windows console code page (cp932) could not print a non-ASCII character in a log line. It had worked every time I ran it by hand.&lt;/p&gt;

&lt;p&gt;A job is not tested until it has run under the same scheduler, user, locale and encoding it will use in production, and its failure reaches a person instead of a log file.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Automation solved posting, not reach
&lt;/h2&gt;

&lt;p&gt;A previous fully automated X setup published 33 posts. The median impressions were about 5. The automation worked perfectly; nobody saw the output.&lt;/p&gt;

&lt;p&gt;Since then, I measure replies separately from posts. In my current numbers, short replies on relevant threads get several times the impressions of my own scheduled posts. Agents can draft and schedule. Being part of a conversation still takes a person.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rule of thumb
&lt;/h2&gt;

&lt;p&gt;If any of these is a "no", the agent runs in dry-run mode until it is a "yes". It is slower, and it is far cheaper than cleaning up after something that acted on its own.&lt;/p&gt;

&lt;p&gt;I turned the full list into a one-page checklist with 25 checks across 7 areas. It is free: &lt;a href="https://neuralalpha.gumroad.com/l/agent-ops-preflight?utm_source=devto&amp;amp;utm_medium=article" rel="noopener noreferrer"&gt;Agent Ops Pre-Flight Checklist&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I write here weekly about running AI agents and automations in production: what broke, what I check now, and what it cost. Not financial, legal or security advice. Adapt everything to your own systems.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://neuralalphaai.substack.com/p/seven-checks-before-i-let-an-agent" rel="noopener noreferrer"&gt;NeuralAlpha&lt;/a&gt;. I write weekly about running AI agents in production.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>automation</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
