Skip to content

Build1 publisher3 min readPublished

A solo operator gates six agent commands because his build folder is his web root

The rules on this production server track deployment topology rather than agent behaviour: a build is a deploy when nginx reads dist, and Prisma will drop indexes it never knew were there. Only one of the rules is enforced by anything but habit.

The Engineer · Build desk

Illustration accompanying A solo operator gates six agent commands because his build folder is his web root

What happened

  • A solo operator in Diakopto, Greece, runs 42 domains, several SaaS platforms and a fleet of chat assistants whose code was mostly written by AI agents working over SSH on the server that serves live users.
  • Every production change starts as a file: the agent audits read-only, then writes a PROPOSED.md naming the change, its blast radius, the rollback steps and the checks that will prove it worked.
  • Six actions each require their own explicit approval, among them pm2 restart, nginx changes, database migrations, git push and publishing anything.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • constraint The build gate only pays for itself where a web server reads the build output directory; behind a pipeline that promotes an artifact, the same rule adds a review round trip and buys no safety.
  • exposure Wherever a push triggers a deployment, every token, CI job and agent with commit rights holds deploy rights, which makes the repository trigger a wider door than the shell the agent is sitting in.
  • contradiction The rulebook is presented as lessons from things going wrong, but its two sharpest lessons came from non-events: a change that passed every check, and a gateway that ran fine for months on its fallback.

The gate that looks excessive is `npm run build`, and the reason is topology, not the command. Several of the frontends on his server are read straight out of their `dist/` folders [9]. nginx serves whatever the bundler wrote there. So an agent that runs a build to check for compile errors has published whatever was on disk to every visitor [9]. Nothing in the command string says deploy. The path from the command to the users does.

That is also the test for whether the rule transfers. If your build emits an artifact that a separate release step later promotes, gating the build buys you a round trip and nothing else. If a web server is pointed at the build output directory, the gate is the only thing standing between a syntax check and a release. Same command, two blast radii, and the difference lives in an nginx config file.

The Prisma rules have the same shape. That database carries partial unique indexes written in raw SQL, because the Prisma schema does not express them the way he needed [12]. Prisma holds no record of them, so any tool that reconciles the model file against the live database computes a difference and offers to remove what it cannot see [12]. `prisma migrate dev`, on detecting drift between migration history and the real database, can answer by resetting it, which he notes is a shrug on a laptop [11]. `prisma db push` is out because it bypasses migration history entirely [13]. What replaces both is fixed: provider snapshot, `pg_dump -Fc` into /var/backups, a dated handwritten `.sql` applied with `psql`, `schema.prisma` edited to match, `npx prisma generate`, then a restart he approves [14]. Two independent copies of the data exist before the first write reaches a table [15].

The strongest rule in the post is about tests. He asked for a test proving client A can never read client B's cached data, and it passed [17]. Then the cache was made global on purpose, the test failed loudly, and that is the only reason he trusts it [17]. His generalisation: make the agent show a security test failing against broken code before you believe it passing against working code [18]. A negative control, cheap, and skipped constantly.

The chat gateway audit is that same failure mode one layer out. Primary model provider plus fallback, everything apparently working, and the audit found the primary had never worked on that gateway: a dead key first, then a retired model name [19]. A fallback converts a configuration error into latency and spend that nobody reads.

Then the terminal rule, which is the least technical and the most useful. Three things can run commands: his Mac, the server, and the agent [16]. Every command he receives is labeled with where it runs, one at a time, because he has pasted an `scp` from ~/Downloads into the server terminal and a `sudo` into his Mac [16].

None of this depends on the agent being trustworthy, and exactly one rule is enforced by machinery rather than by habit: the two GitHub Actions that deployed on every push to `main` are switched off [10]. The stop is a sentence at the end of the agent's instructions, "write it, report, stop" [6], added after, by his account, an agent applied a change while his editor was frozen mid-read [5]. For one operator who reads every proposal before saying GO [4], that trade holds. Its ceiling is reading time.

What to watch

  • Whether the agent ever gets an OS account that cannot restart pm2 or write to the served dist directories, which would move the stop from instructions into permissions.
  • Whether the chat gateway's primary provider is actually repaired, or the fallback stays the de facto primary with the config left as written.
  • Whether Prisma's schema gains support for partial unique indexes, which would remove the reason for the handwritten SQL sequence.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories