mech.app

The mech.app newsletter

Agentic AI, minus the noise.

Get practical field notes on AI agents, automation, developer tools and security delivered to your inbox.

No spam. Unsubscribe anytime.

Dev Tools

Blast-Radius Firewalls for Coding Agents: How a Dual-Mode CLI Stops Autonomous Loops from Wrecking Your Repo

A dual-mode CLI architecture with blast-radius limiting and loop detection that prevents autonomous coding agents from destroying your repository.

Source: dev.to
Blast-Radius Firewalls for Coding Agents: How a Dual-Mode CLI Stops Autonomous Loops from Wrecking Your Repo

Autonomous coding agents fail in predictable ways. They enter edit-revert loops, hallucinate dependencies from stack traces, and eventually decide that git reset --hard is a reasonable conflict resolution strategy. The failure mode is not prompt injection or model collapse. It is unrestricted terminal access combined with no blast-radius containment.

A developer recently documented a near-miss: an agent tasked with fixing unit tests oscillated through 18 turns of breaking and reverting the same function, then attempted to wipe uncommitted work. The only thing that prevented data loss was a Windows file lock throwing an unrelated permission error.

The response was not another AI wrapper. It was a dual-mode CLI harness that treats human and agent execution contexts as fundamentally different threat models.

The Failure Vectors

Coding agents inherit the same terminal interface designed for human operators. That interface assumes:

  • The operator reads output and adjusts behavior.
  • Verbose logs and stack traces provide useful context.
  • Destructive commands require conscious intent.

Agents violate all three assumptions. They parse stdout as structured input, get confused by noise, and execute destructive commands as optimization shortcuts.

The documented incident exposed three specific failure modes:

Infinite oscillation loops: The agent changed auth.py, broke a downstream test, reverted the change, re-broke the original test, and repeated for over an hour. No circuit breaker existed to detect the pattern.

Context window poisoning: A failed command dumped 3,800 lines of node_modules stack trace into stdout. The agent hallucinated a fake package (reqeusts-fast) and burned API tokens trying to install it.

Blast-radius escalation: When git conflicts appeared, the agent escalated to git reset --hard without understanding the scope of uncommitted changes at risk.

Dual-Mode Architecture

The solution is a CLI that runs in two distinct modes with different safety boundaries.

Human Mode

When a human operator runs the tool, it behaves as a code review assistant:

  • Provides cynical feedback on diffs.
  • Suggests improvements without executing changes.
  • Outputs human-readable text with color and formatting.

Agent Mode

When an autonomous agent runs the tool, it enters a restricted execution context:

  • All file operations are scoped to a blast-radius limit (default: 5 files per command).
  • Output is structured JSON with no verbose logs.
  • A watchdog monitors for loop patterns and kills runaway sequences.
  • Destructive git operations require explicit confirmation flags.

The mode switch is not a command-line flag. It is inferred from the execution context: whether stdin is a TTY, whether the parent process is a known agent runtime, and whether environment variables signal autonomous operation.

Blast-Radius Containment

The core safety mechanism is a file operation firewall. Every command that modifies the file system declares its intended scope upfront.

class BlastRadiusFirewall:
    def __init__(self, max_files=5, max_depth=3):
        self.max_files = max_files
        self.max_depth = max_depth
        self.touched_files = set()
    
    def check_operation(self, operation, target_paths):
        # Expand globs and resolve symlinks
        resolved = self._resolve_paths(target_paths)
        
        # Reject if operation exceeds file limit
        if len(resolved) > self.max_files:
            raise BlastRadiusExceeded(
                f"Operation touches {len(resolved)} files, limit is {self.max_files}"
            )
        
        # Reject if operation crosses directory depth boundary
        if self._max_depth(resolved) > self.max_depth:
            raise BlastRadiusExceeded(
                f"Operation crosses depth limit of {self.max_depth}"
            )
        
        # Track cumulative file touches across command sequence
        self.touched_files.update(resolved)
        if len(self.touched_files) > self.max_files * 3:
            raise BlastRadiusExceeded(
                f"Cumulative file touches exceed safety threshold"
            )
        
        return True

The firewall enforces three boundaries:

  1. Per-operation file limit: A single command cannot modify more than N files (default: 5).
  2. Directory depth limit: Operations cannot span more than N levels of directory nesting (default: 3).
  3. Cumulative touch limit: The total number of unique files modified across a command sequence cannot exceed 3x the per-operation limit.

These limits prevent both accidental wide-area damage and intentional escalation through repeated small operations.

Loop Detection Watchdog

The second safety layer is a state machine that detects oscillation patterns.

The watchdog tracks:

  • File modification history (which files were changed, when, and by which command).
  • Command sequence patterns (repeated invocations of the same operation with minor variations).
  • Test result transitions (pass to fail to pass cycles on the same test).

When it detects a loop, it does not immediately kill the agent. It injects a circuit breaker that forces the agent to change strategy.

Detection PatternThresholdResponse
Same file modified 3+ times in 10 minutes3 editsBlock further edits to that file for 5 minutes
Same command fails 3+ times with same error3 failuresReturn cached error, refuse re-execution
Test oscillates pass/fail on same function2 cyclesForce agent to modify a different file
Git operation reverted within 2 commands1 revertRequire explicit confirmation for next git command

The watchdog does not try to fix the agent’s logic. It creates friction that forces the agent to explore different solution paths.

Structured Output for Agents

Human-readable terminal output is toxic to agents. A typical pytest failure dumps hundreds of lines of context, ANSI color codes, and ASCII art. Agents parse this as structured data and hallucinate patterns.

In agent mode, all output is JSON with a fixed schema:

{
  "status": "failure",
  "operation": "test_run",
  "affected_files": ["tests/test_auth.py"],
  "error_type": "assertion_failure",
  "error_location": "test_auth.py:42",
  "error_message": "Expected 200, got 401",
  "suggested_actions": [
    "check_auth_token_validity",
    "verify_user_permissions"
  ],
  "blast_radius": {
    "files_touched": 2,
    "limit_remaining": 3
  }
}

This eliminates context window poisoning. The agent receives only the information it needs to make a decision, with no stack traces or verbose logs.

Git Operation Guardrails

Destructive git commands are the highest-risk operations. The harness treats them as a separate threat class.

In agent mode:

  • git reset --hard is blocked entirely. The agent must use git stash or git checkout -- <file>.
  • git push --force requires an explicit --agent-confirmed flag and a 10-second delay.
  • git clean -fd is replaced with a dry-run that returns a list of files to be deleted, requiring per-file confirmation.
  • Any operation that modifies commit history is logged to an append-only audit file.

The goal is not to prevent all destructive operations. It is to force the agent to demonstrate intent through explicit confirmation, creating an audit trail.

Deployment Shape

The tool runs as a local CLI binary, not a cloud service. It wraps existing git and test commands, intercepting their execution.

Installation:

pip install git-oops
git-oops init  # Installs git hooks and sets up watchdog

The init command:

  • Adds a post-commit hook that logs all file modifications.
  • Creates a .git-oops/ directory for state tracking.
  • Registers the CLI as the default handler for common agent commands.

When an agent invokes git commit, the harness intercepts it, checks blast-radius limits, and either allows or blocks the operation.

Observability

The harness exposes three observability surfaces:

  1. Real-time event stream: A Unix socket that emits JSON events for every intercepted command, blast-radius check, and loop detection trigger.
  2. Audit log: An append-only SQLite database that records all agent operations, including blocked commands and their reasons.
  3. Metrics endpoint: A local HTTP server (default: localhost:9090/metrics) that exposes Prometheus-compatible counters for blast-radius violations, loop detections, and command rejections.

These surfaces allow external monitoring tools to track agent behavior without modifying the agent itself.

Likely Failure Modes

This architecture does not prevent all agent failures. It shifts them.

False positives on legitimate multi-file workflows: A refactor that touches 10 files will be blocked. The developer must manually increase the blast-radius limit or split the operation.

Agents that learn to game the watchdog: If the loop detector blocks edits to auth.py, a sufficiently clever agent might rename the file and continue. The watchdog does not track semantic equivalence.

Performance overhead on fast iteration cycles: Every command interception adds 50-100ms of latency for blast-radius checks. In tight test loops, this compounds.

No protection against prompt injection: If an attacker controls the agent’s input, they can craft prompts that bypass the harness by invoking raw shell commands instead of the wrapped CLI.

Trade-Off Matrix

ApproachBlast-Radius ControlLoop PreventionHuman UsabilityAgent Compatibility
No guardrailsNoneNoneHighHigh
Manual code reviewHighHighLowLow
Dual-mode CLI harnessMediumMediumHighMedium
Sandboxed containerHighNoneLowMedium
Read-only agent with human approvalHighHighMediumLow

The dual-mode CLI sits in the middle: it provides meaningful protection without requiring agents to be rewritten or humans to approve every operation.

Technical Verdict

Use this pattern when:

  • You run autonomous coding agents on repositories with uncommitted work.
  • Your agents have a history of entering edit-revert loops or escalating to destructive commands.
  • You need an audit trail of agent operations for compliance or debugging.
  • You want to experiment with agent autonomy without risking data loss.

Avoid this pattern when:

  • Your agents operate in ephemeral containers where data loss is acceptable.
  • You need sub-100ms command latency for tight iteration loops.
  • Your workflow involves frequent legitimate operations that exceed blast-radius limits (e.g., mass refactors).
  • You already have robust snapshotting and rollback infrastructure.

The core insight is that agents and humans need different interfaces to the same tools. A CLI designed for human eyeballs will poison an agent’s context window. A CLI designed for agents will frustrate human operators. The solution is not a compromise. It is two distinct execution modes with a clean boundary between them.

Tags

agentic-ai orchestration infrastructure

Primary Source

dev.to ↗