← Blog
Industry2026-07-29

Building deep tech from Bulgaria: what changes when the coding agent cannot merge its own work

Solo founder, AI coding agents and EuroHPC. The part that matters is the process that catches the agents being wrong before it reaches main.

#deep-tech#engineering-governance#euro-hpc#aiagents#bulgaria

Two weeks ago, one of the AI coding agents I work with ran git clean -fd on a dirty working tree. It deleted 186 uncommitted test files. No malice, no bug in the usual sense — it just did what the command does.

That incident is why the process I’m about to describe exists.

I’m a solo founder building NEMO, a physics surrogate for multi-physics engineering simulation, out of Bulgaria. No engineering team. My leverage is AI coding agents doing a large share of the implementation, running on a mix of local hardware and EuroHPC time. That combination is common enough now that it’s not really the interesting part. The interesting part is what breaks if you let it run unsupervised, and what I built to stop it from breaking things I can’t see.

The compute stack is unglamorous on purpose. A Proxmox host with a consumer RTX 3090 in a container handles smoke tests — the “does this even run” pass. A self-hosted GitLab is the CI authority: nothing merges without it. The real training runs go to EuroHPC Discoverer, Bulgaria’s petascale machine, under a 5,000 GPU-hour allocation. Discoverer’s queue gives each job a 4-hour wall time, full stop — no exceptions for a training run that wants 40 hours. So the long runs are chain-resumed job arrays: checkpoint, requeue, resume, repeat. One recent retrain took 100,000 steps that way, in 4-hour bites, because the corpus and the token layout had changed enough that resuming from the previous model wasn’t valid — it had to start from scratch. That’s not an elegant design choice, it’s what a hard queue limit forces you into, and it works.

Locally, the MOOSE solver — the ground-truth FEM engine that every surrogate prediction gets checked against — runs at about 36 seconds per solve, which is roughly 140,000 solves a day of headroom if I ever needed it. I mention the number because in this kind of work, time isn’t measured in weeks. It’s measured in GPU-hours and solve counts. I try not to promise dates, because I don’t actually control them — the queue does.

Here’s the part that actually matters: agents multiply output, they don’t multiply judgment. An agent that writes code fast is only useful if something independent of that agent can tell you when the code is wrong. So the process is deliberately adversarial to the agent that wrote the change:

  • Every change gets classified into a risk tier (contained, shared-contract, or high-risk: auth, migrations, infra, policy).
  • Every change needs fresh evidence — tests that actually ran, not a summary of tests that supposedly ran.
  • The coding agent cannot merge its own work. Ever. Not with elevated permissions, not with a bypass flag.
  • For anything above the lowest risk tier, a merge requires a human Ed25519 signature bound to the exact commit SHA — not “approved this branch,” but “approved this specific committed state.” A rebase, a new commit, an amended commit: the approval is dead, get a new one.
  • Merge authority itself sits with an isolated bot that revalidates the signature, the pipeline result, and the commit SHA immediately before merging. A green result on my laptop is not evidence of anything the system accepts.

None of that existed before the git clean -fd incident. It’s not there because I distrust the specific agent — it’s there because I trust the process, not the actor, and I built the process only after learning I needed to.

Two smaller lessons became hard rules, the expensive way. First: enable double-precision floating point on every FEM solve path, before any array is even created. A single ill-conditioned solve with penalty boundary conditions can carry a condition number around 10^12, while float32 gives you roughly 10^7 of precision — six orders of magnitude short. The result isn’t slightly wrong, it’s arbitrary, and the usual sanity checks don’t catch it because they’re checking the wrong thing. Second: reconcile the sampling parameters of two datasets before you compare models trained on them. I once compared a model on 8,192 points per shape against a baseline that had seen 200,000 — and got a confident, entirely wrong conclusion about which one was “better.” The two datasets weren’t measuring the same thing; the comparison was the bug.

None of this is a story about AI agents being unreliable in some special way. It’s a story about what any fast, tireless contributor needs around it before you can actually rely on its output: independent verification, a human in the loop at the moments that matter, and rules that don’t bend just because the change looks small.

I’d be curious how other small teams — not just AI-adjacent ones — are drawing the line between “the agent decides” and “a human decides,” especially where the failure mode is silent rather than loud.

Discuss NeuroCAD as a pilot or investment opportunity.

Working MVP/demo is available for qualified conversations.

Contact the Founder