{"slug": "i-accidentally-built-a-forward-deployed-engineer-s-field-kit", "title": "I accidentally built a forward-deployed engineer's field kit", "summary": "A developer discovered that their architectural choices for AI tools, initially framed as bundler or preference issues, were actually solving deployment problems for forward-deployed engineers. By replacing an SDK with a minimal SSE parser and adopting browser-only, BYOK, and no-backend designs, they inadvertently created tools that are easier to debug and pass security reviews in customer environments. The developer argues that these constraints—reducing dependencies, keeping keys client-side, and avoiding servers—are the same ones that make tools viable in high-security, on-site deployments.", "body_md": "A year ago I deleted `@anthropic-ai/sdk`\n\nfrom a project and wrote about 150\n\nlines of TypeScript to replace it.\n\nThe reason I gave myself was honest and boring. The SDK pulled `node:fs/promises`\n\nin through an agent-toolset module, which broke the browser bundle. I could have\n\nwaited for a browser-clean entry point. Instead I hand-rolled an SSE parser and\n\n[wrote a post about why](https://ferhatatagun.com/blog/browser-only-claude-streaming).\n\nI filed that away as a bundler story.\n\nThen I read a line in a piece about tooling for forward-deployed engineers — the\n\npeople who get sent into a customer's building to make an AI deployment actually\n\nwork. Roughly: every framework dependency is something the customer's security\n\nteam will ask about, and bare-metal code is easier to debug in an environment\n\nthat isn't yours.\n\nSame decision. Same reasoning. Different discipline, different job title,\n\ndifferent problem entirely — except it wasn't a different problem.\n\nI hadn't been solving a bundler issue. I'd been solving a *deployment* problem\n\nwithout ever naming it, which is why I mistook it for taste.\n\nThis post is what happened when I went back through every architectural decision\n\nin the five tools I've shipped and asked a question I'd never asked: what\n\nconstraint was actually operating here?\n\n**TL;DR**\n\nHere's the thing about the SDK call that I got wrong at the time.\n\nI framed it as: *the SDK doesn't work in my environment, so I'll write the\nminimum that does.* Reasonable. What I actually did was reduce the tool's\n\n`fetch`\n\nand a `TextDecoder`\n\n— and the consequence of that,That property is worthless when you're debugging on your own laptop with a\n\ndebugger attached and all the time in the world.\n\nIt is the whole game when you're on a call with someone else's engineer, in\n\nsomeone else's network, and they ask why the response cut off, and the honest\n\nanswer needs to arrive in the next ninety seconds.\n\nI didn't build it for that. But that's what it is.\n\nOnce I started looking, the pattern didn't stop.\n\n**BYOK — bring your own key.** What I told myself: I don't want to run a proxy,\n\nI don't want to hold anyone's credentials, and I *really* don't want to pay for\n\nstrangers' tokens. All true. What it actually is: the customer's key never\n\nleaves their browser and their prompt never touches infrastructure I control.\n\nThere's no data-processing agreement to negotiate because there's no data\n\nprocessing. The \"I'm too lazy to run a backend\" version and the \"this passes a\n\ncompliance review\" version are the same architecture.\n\n**No backend at all.** What I told myself: static hosting is free and I don't\n\nwant to maintain servers for a side project. What it actually is: there is no\n\nserver to threat-model, no attack surface to document, no uptime story to tell,\n\nand no vendor security questionnaire that takes six weeks to clear. The thing a\n\nsecurity team can approve fastest is the thing that doesn't exist.\n\n**Every tool is a URL.** What I told myself: it's easier to share a link than to\n\ntell someone to clone a repo and run `npm install`\n\n. What it actually is: zero\n\ninstall. Nothing enters the customer's machine. The people who most need a\n\ndiagnostic tool are exactly the people who are least permitted to install one.\n\n**Cost rendered live, not logged.** What I told myself: the number is\n\ninteresting and I wanted to see it move. What it actually is: the person who\n\napproves the renewal can read it without asking anyone. I made [an entire\nargument](https://ferhatatagun.com/blog/prompt-caching-nobody-measures) about\n\nFour decisions. Four reasons I gave at the time that were true but shallow. One\n\nconstraint underneath all of them that I never said out loud.\n\nI don't want to make this sound cleaner than it is, so let me argue against\n\nmyself for a second.\n\nBrowser-only is a genuinely bad choice for a lot of software. You get no\n\nserver-side secret handling. You fight CORS constantly — and for some providers\n\nyou simply lose, because they don't send the headers and there's nothing you can\n\ndo about it from a tab. You have no durable storage worth the name, no scheduled\n\njobs, no background processing, no way to do anything computationally serious.\n\nYou can't build a product this way. I'm not going to pretend you can.\n\nBut none of those limitations bind on a *diagnostic instrument*.\n\nA multimeter doesn't need a database. The tool that tells you why the system is\n\nbehaving strangely is not the system. It has to be trustworthy, portable, and\n\nreadable — and it has to work at the exact moment when everything heavier is\n\nunavailable to you. Every constraint I listed as a cost is irrelevant to that\n\njob, and two of them (no storage, no server) are the reason it can be used at\n\nall in a place that would reject a real deployment.\n\nThe limitation and the qualification are the same fact viewed from two sides.\n\nFDE tooling gets described, fairly consistently, in four categories: agent\n\norchestration, evaluation, guardrails, and observability. I went and put my\n\nthings in the boxes.\n\n| Category | Tool | What it does |\n|---|---|---|\n| Observability |\n|\n\nThree categories covered, one pre-flight bonus, one hole.\n\nI want to be careful here, because there's a version of this post that's a\n\nportfolio tour with an FDE hat on, and that version is worthless. So: I didn't\n\nplan this map. It's a retrofit. The tools were built one at a time over a couple\n\nof weekends each, and the only through-line I could have articulated at the time\n\nwas [\"make the Claude API\nlegible\"](https://ferhatatagun.com/blog/four-tools-in-two-weekends). The\n\nGuardrails is missing, and it's the one that would hurt most in the field.\n\nGuardrails is the layer that keeps model output inside a shape your code can\n\nsafely consume. You ask for `{\"risk\": \"high\"|\"medium\"|\"low\", \"score\": 0-100}`\n\n.\n\nWhat actually comes back, across enough calls:\n\n`\"HIGH\"`\n\ninstead of `\"high\"`\n\n— enum drift`\"very high\"`\n\n— an enum value that doesn't exist, invented on the spot`\"score\": \"85\"`\n\nas a string, silently breaking arithmetic downstream`score`\n\nmissing entirelyEvery one of those either crashes your parser or, worse, doesn't — and quietly\n\nputs a wrong category on someone's dashboard.\n\nThe reason this needs an instrument rather than a unit test is that the failures\n\nare **distributional**. You run it once, it works, you ship. Then one call in\n\nforty returns a hallucinated enum, and you never see it, because you looked at\n\none sample. What you need is the failure *rate*, broken down by failure type,\n\nacross fifty runs. That's a different question than \"does it work.\"\n\nSo that's the sixth tool, and it's the honest one to build next: define a\n\nschema, run a prompt against it N times, show the distribution of ways it\n\nbreaks. Same constraints as the rest — browser-only, BYOK, no backend, because\n\nby now those aren't a preference, they're the spec.\n\nStrip out my repos and there's one idea left worth keeping.\n\nMost side projects have no constraint. That's why they read as toys — not\n\nbecause they're small or unfinished, but because nothing about them was *forced*.\n\nAny decision could have gone the other way and nothing would have broken. A\n\nreader can feel that.\n\nA tool with an articulated constraint reads completely differently, even when\n\nit's fifty lines. \"This runs in a tab because it has to work where nothing can\n\nbe installed\" is a design brief. \"This is a React app\" is not. The first one\n\ntells you what the author was up against; the second tells you what they typed.\n\nThe uncomfortable part, for me, is that I had the constraint the whole time and\n\ncouldn't name it. I shipped five things under a rule I was following\n\nunconsciously, and because I never said it out loud, I also couldn't tell you\n\nwhat the work was evidence *of*. It looked like five small tools. It was a\n\nposition.\n\nIf you're a frontend engineer looking at the current AI hiring market and\n\nwondering how to become legible to it: you very likely already have\n\nconstraint-shaped work sitting in your repos. The move isn't to build something\n\nnew. It's to go back and figure out what you were actually solving for, and then\n\nsay it in the README.\n\nMine took a year and a stranger's sentence about security teams.\n\n*Part two of a series on the last mile of enterprise AI. Part one is\nNobody's model failed. The interface did.\nPart three is about the thing I keep saying and haven't yet defended properly —\nthat on this kind of work, the deliverable isn't the prompt, it's the eval.*\n\n*This post is mirrored from ferhatatagun.com/blog/accidental-fde-field-kit — that's the canonical URL.*\n\n**More from the same place:**\n\nHappy to discuss here or on the canonical post — both threads stay open.", "url": "https://wpnews.pro/news/i-accidentally-built-a-forward-deployed-engineer-s-field-kit", "canonical_source": "https://dev.to/ferhatatagun/i-accidentally-built-a-forward-deployed-engineers-field-kit-khi", "published_at": "2026-08-10 07:48:53+00:00", "updated_at": "2026-08-10 08:16:26.500692+00:00", "lang": "en", "topics": ["developer-tools", "ai-tools", "ai-infrastructure"], "entities": ["Anthropic", "Ferhat Atagun"], "alternates": {"html": "https://wpnews.pro/news/i-accidentally-built-a-forward-deployed-engineer-s-field-kit", "markdown": "https://wpnews.pro/news/i-accidentally-built-a-forward-deployed-engineer-s-field-kit.md", "text": "https://wpnews.pro/news/i-accidentally-built-a-forward-deployed-engineer-s-field-kit.txt", "jsonld": "https://wpnews.pro/news/i-accidentally-built-a-forward-deployed-engineer-s-field-kit.jsonld"}}