← Binderdex dev log

2026-11-05

Production Left the Laptop

ai-agentsautomationinfra

Flat editorial illustration of a laptop handing a workflow over to a grid of server racks, one amber path glowing through the handoff

I run Binderdex the card market site solo, and for months "production deploy" meant "the owner is awake and at his desk." Schema push? His Mac. Mobile rollout widening? His Mac. One read-only query to check on a job? You get the idea. An agent session working overnight could do everything up to the last mile, then stall until morning.

Last night that finally changed. Four commits moved the last routine production actions into GitHub Actions, and the interesting part is what they had to build around the move.

Why the laptop was load-bearing

The blocker was never tooling. Auto mode on my Mac treats "talk to production" as a deploy-class action, and my agent's allow rules kept getting overruled by the safety layer. So every widening of a mobile rollout, every OTA publish, every schema push waited for a human to type the command. The fix wasn't to loosen the rules. It was to move the action somewhere the rules already make sense.

That somewhere is a GitHub environment. Jobs running from main in the production-ops environment assume a least-privilege role: it opens the same tunnel a maintainer uses, connects as a read-mostly database user, touches exactly the queues and log groups one workflow needs. No wildcard actions, and a test pins all of it.

On top of that role sit four workflows, each one boring on purpose:

  • Rollout editing: changes the percentage of an already-published update group. It can never publish.
  • OTA publish: goes through the existing release scripts, so preflight, fingerprint checks, and source map uploads still run.
  • Read-only query: one statement, validated before it runs, in a read-only session with a timeout and a row limit.
  • Schema push: the one that earned a whole subsystem.

The additive-only rule for schema changes

Schema pushes were the scariest thing on the list, because a schema push can destroy data. The owner decision was: unattended pushes are fine if every statement is additive. So the CI twin of the normal push runs Drizzle's plan through a checker that refuses anything destructive:

// allowed: new tables, nullable/defaulted columns,
// indexes, constraints, enum values
// refused: drops, renames, type changes,
// NOT NULL without a default, procedural blocks

Surviving statements apply in one transaction with a five-second lock timeout, then a verify pass re-reads the schema and re-plans to zero. The test suite proved the refusal path too: add a column meant to be dropped, and the checker kills it.

Here's the whole shape of the migration:

The owner's MacGitHub Actionsleast-privilege IAM roleadditive-only DDL checkproduction Postgresmobile rollouts + OTA overnight tunnel one transaction no publish,no laptop

The bug that made me smile

The first dry run of the new pipeline lost its --dry-run flag silently. pnpm 11 forwards a literal -- to the script, so the argument parser saw everything after it as positional. The flag vanished, and then the production guard refused the run: production writes require an explicit confirmation flag. Nothing was enqueued, which is exactly what a dry run is supposed to guarantee. The guard meant to stop accidents was doing its job against the tooling itself.

The lesson generalizes: when a guard refuses something you didn't mean to do, log what actually arrived in the script. "The flag is in the command" and "the flag reached the parser" are different claims.

What it unlocked

A night agent can now widen a rollout, publish an OTA, run a read-only sanity query, and push an additive schema change, each behind its own workflow and its own guardrails. The first real run moved a rollout from 50% to 100% at 1 a.m. while I was doing something else entirely.

If you're a solo founder with an agent doing overnight work, the pattern is: don't grant the agent your powers. Build the smallest legitimate channel for each action, put the guard in the channel, and let the laptop go to sleep.

this is the build log of binderdex · www.binderdex.com · all entries · essays