{"slug": "the-30-second-check-that-stops-you-building-what-already-exists", "title": "The 30-second check that stops you building what already exists", "summary": "An engineer at Pulsed Media recounts how an AI coding agent built a bespoke tool for network-switch CLI automation that duplicated existing solutions like Netmiko, Ansible, and Oxidized. The team now mandates a 'reuse gate' before any build to check for existing internal or external tools, emphasizing that reviews must first question whether a tool should exist at all.", "body_md": "*A short, honest engineering retro. I let an AI coding agent (and myself) build a bespoke tool for a job that Netmiko, Ansible, and Oxidized already do. The bug wasn't in the code. It was skipping one question before the first line.*\n\nThe task looked small: give an agent a way to drive network-switch CLIs, send a command, wait for the expected output, react. So it built one. A tidy little wrapper around `tmux`\n\n: open a session, `send-keys`\n\nthe command, poll `capture-pane`\n\nuntil a pattern matched or it timed out, and stream everything to an audit log.\n\nIt got a design review. It got an architecture note. It got an adversarial pass that found a real bug (the capture only read the *visible* pane, so long output silently timed out). It got a fix. It got tests.\n\nThen someone asked the only question that mattered, the one nobody had asked yet:\n\n\"So this leaves almost nothing, because Netmiko already covers switches?\"\n\nYes. It did. `Netmiko`\n\n(multi-vendor SSH for network gear), `Ansible`\n\n's `network_cli`\n\nconnection plugin, and `Oxidized`\n\n(config backup) already do send-command-and-expect against switches, at fleet scale, with per-vendor quirk handling nobody wants to reimplement. The bespoke `tmux`\n\ndriver was a worse version of tools that have existed for years.\n\nA session's worth of building, reviewing, and fixing. All of it on something that should never have been written.\n\nAt [Pulsed Media](https://pulsedmedia.com) we run a lot of automation over our own hardware, and we lean on LLM tooling in day-to-day ops, so this failure mode isn't hypothetical for us. It's a standing tax. AI agents are *very* good at building. That's exactly the problem.\n\nThe fix is embarrassingly cheap. Before you (or your agent) build anything with a name (a \"driver\", a \"client\", a \"manager\", a \"helper\"), run the reuse gate:\n\n```\n# 1. Does something in THIS repo already do it? (5 seconds)\nrg -l \"expect|send.?command|capture-pane|pexpect\" .\n\n# 2. Does a mature EXTERNAL tool already do it? (25 seconds)\n#    literally a web search: \"python send command expect network switch\"\n#    → netmiko, ansible network_cli, oxidized, pexpect, expect(1)\n```\n\nThat's it. Two commands, half a minute. If either returns a real answer, you are no longer deciding *how to build*. You are deciding *whether to adopt*. Those are different projects, and the second one is usually a config file instead of a codebase.\n\nThe reason this gate gets skipped is not laziness. It's that building *feels* like progress and searching feels like a detour. An AI agent amplifies the feeling: it will happily produce a clean, tested, well-structured implementation of the wrong thing, and every artifact it generates (the tests, the review, the docs) makes the wrong thing look *more* legitimate, not less.\n\nThe reuse gate is the counterweight. It runs **before** the first line, because after the first line, sunk cost takes the wheel.\n\nHere's the part that stung. The tool got reviewed, thoroughly. Adversarial review, architecture doc, the works. And all of it was aimed at *how well it was built*.\n\nNot one of those reviews asked *whether it should be built*.\n\nThis is a general trap, and it's worth naming: **your review process can be rigorous and still be pointed at the wrong question.** A review that only asks \"is this well-designed?\" will bless a beautifully-designed thing that shouldn't exist. The \"should this exist at all?\" check has to come *first*, at design entry. Otherwise every downstream review inherits the false premise and polishes it.\n\nIf you use an \"authority/reuse gate\" in your review templates, put it at the **top**, before the design critique, phrased as a hard question: *does an existing tool, ours or third-party, already produce this output?* If yes, the default answer is **don't build**: adopt, and justify any reimplementation explicitly. At Pulsed Media we now treat that as the first gate, not a footnote, precisely because we learned it the expensive way.\n\nOnce a build has momentum, your brain will manufacture reasons to keep going. Watch for these three, the ones that got me:\n\n**1. The misread policy.** Our shop has a \"no Python for new code\" rule. I told myself that ruled out Netmiko (which is Python) and therefore a custom tool was *necessary*. Wrong: the rule blocks *writing* Python in our repo. It does not block *consuming* a mature Python tool as external infrastructure, and we already run plenty of third-party services in other languages. I had turned a real policy into a fake constraint that happened to justify the thing I was already building. When a policy conveniently makes your current path the only path, re-read the policy.\n\n**2. \"The boss said we need it.\"** An operator did say \"we need this.\" But \"we need the capability\" authorizes *solving the need*, and adopting an existing tool solves it. \"We need it\" is not \"we need *you to build it*.\" A stakeholder's yes to a goal is not a waiver of the reuse gate.\n\n**3. Sunk cost, wearing a lab coat.** Once the tests passed and the review came back clean, stopping felt like *wasting* good work. But the tests passing on a tool that shouldn't exist is not a reason to keep it. It's just a well-tested mistake. The cost is already spent; keeping the tool spends more (maintenance, the next person's confusion) to avoid admitting the first spend.\n\nThe reuse gate is easy to wave at and hard to actually run, so here is what it looks like applied to three real automation needs, the kind that come up constantly when you run your own infrastructure.\n\n**Driving switch and router CLIs.** This was the trap I fell into. The need is real: old network gear has no clean API, so you script the CLI, send a command, wait for the expected output, answer a pager. Thirty seconds of searching surfaces Netmiko (multi-vendor SSH with per-vendor prompt and paging quirks already solved) and Ansible's `network_cli`\n\nconnection plugin. Both are mature, both handle the vendor edge cases you have not thought of yet, and both are consumable as external infrastructure. The gate answer is adopt, not build.\n\n**Backing up device configs.** The need is a versioned history of every config change. It is tempting to write a loop that SSHes in, runs `show running-config`\n\n, and commits the output to git. Oxidized does exactly that, across dozens of vendors, with a web UI and a git backend, and it has done it reliably for years. Again: adopt.\n\n**Recovering a stuck text console.** Here the gate answer is genuinely thinner. Driving an interactive rescue shell (an initramfs prompt, a busybox recovery, a manual fsck) is rare enough that no single mature tool owns it, but `pexpect`\n\nand the classic `expect(1)`\n\ncover the send-and-expect core. The honest verdict is \"mostly adopt, occasionally glue,\" and even that admission is the gate working: it tells you the custom surface is small, so keep it small.\n\nNotice the pattern. Two of three needs are fully covered by tools that already exist, and the third shrinks to a thin wrapper once you subtract what `pexpect`\n\nalready does. At Pulsed Media we now run the gate on every \"we should build a tool for X\" before a line is written, because the expensive lesson taught us the honest answer is usually \"adopt, and stop.\" The reuse gate does not slow you down. It tells you, in thirty seconds, how much of the thing is actually yours to build, which is almost always less than it feels like at the start.\n\nBefore building anything with a name:\n\n`rg`\n\nthe repo + one web search for the mature tool. 30 seconds.None of this makes you build slower. It stops you building the wrong thing at full speed, which is the failure AI agents make faster and more convincingly than any human ever could. The best code is the code you didn't write because someone already wrote it better.\n\n*If you're building agent systems that generate and ship code in production, or you just want to see what disciplined, own-hardware infrastructure looks like, I run infrastructure and support at Pulsed Media: seedboxes and storage on our own machines in our own datacenter in Finland, on an open-source platform (PMSS, GPL v3), EU jurisdiction, 14-day money-back. We publish our mistakes because the industry needs honest engineering write-ups more than it needs another launch post.*", "url": "https://wpnews.pro/news/the-30-second-check-that-stops-you-building-what-already-exists", "canonical_source": "https://dev.to/vainamoinen/the-30-second-check-that-stops-you-building-what-already-exists-3kap", "published_at": "2026-09-02 14:58:27+00:00", "updated_at": "2026-09-02 15:25:30.117623+00:00", "lang": "en", "topics": ["developer-tools", "ai-agents", "ai-tools"], "entities": ["Pulsed Media", "Netmiko", "Ansible", "Oxidized"], "alternates": {"html": "https://wpnews.pro/news/the-30-second-check-that-stops-you-building-what-already-exists", "markdown": "https://wpnews.pro/news/the-30-second-check-that-stops-you-building-what-already-exists.md", "text": "https://wpnews.pro/news/the-30-second-check-that-stops-you-building-what-already-exists.txt", "jsonld": "https://wpnews.pro/news/the-30-second-check-that-stops-you-building-what-already-exists.jsonld"}}