Skip to main content
  1. writings/
  2. AI-Assisted Data Engineering/

Speed with Lane Discipline

·7 mins·
Table of Contents

Introduction
#

Guardrails are not brakes, they are the lane markers that let me drive fast because I know exactly where the road edges are. The goal is never to slow the agent down on the work that is safe, only to remove the handful of ways it can do something I cannot undo.

The setup chapters gave the agent context and reusable instructions. This part adds the thing that makes that setup safe at real speed, namely hard limits around the actions that can cause lasting damage. This is the differentiator of the whole book, so I want to be concrete. The framing I keep returning to is speed with lane discipline, and the rest of this chapter turns that phrase into actual configuration. The patterns below outlast any specific tool, because they are about where the limits go and why, not about the syntax of the week.

Guardrails Are Lane Markers, Not Brakes
#

A racing driver does not go fast in spite of the barriers, they go fast because of them. The lane markers tell them exactly where the edge is, so they can commit to the corner instead of feathering the throttle out of fear. Guardrails on an agent work the same way. They are not there to make it slower. They are there so I can let it run hard on the ninety-five percent of work that is safe, knowing the few genuinely dangerous moves are blocked by design.

The mental shift that makes this work is to stop asking whether I trust the model not to do something, and start asking whether the model can do it at all. Trust is a hope, and a guardrail is a constraint. The crucial difference is how they fail. Trust fails silently, with no warning until the damage is done. A constraint fails safely, stopping the action before it happens. When the cost of being wrong is high, I want the version that fails safely, every time.

This is the same lane discipline from earlier in the book, made concrete in configuration instead of intention. Reading the diff and owning what ships are habits, and habits are fragile under deadline pressure. Configuration is not. A limit written into the environment holds whether I am rested or exhausted, careful or rushed, which is exactly when I need it most. Good guardrails move the safety from my discipline into the system, so it does not depend on me being at my best.

The Four Layers
#

I think about guardrails in four layers, each catching what the one before it might miss. The first is the agent and the editor, which is the cheapest place to set limits and the one that catches the most. A new session should start unable to run commands or write files until I grant it, the agent should work inside the project only with credential files kept out of reach, and permissions should reset per session so a one-time grant never becomes a standing one.

The second layer is the repository, and it exists because I assume a command will eventually slip past the first layer. The shared branch is protected so nothing lands without a pull request, review and passing checks are required before a merge, and the agent is allowed to commit on a feature branch but not to push. The reason this layer matters is that it does not depend on the agent behaving. It is enforced by the platform, so it holds even when an editor setting is wrong.

The third layer is data and credentials, and it is the one I am strictest about, because data damage is the kind you cannot always undo. The agent gets a role that can read and nothing else, its connection points at a development or staging environment, and production write access simply does not exist where the agent can reach it. The fourth layer is the human gate, a short list of actions dangerous enough that I never automate them no matter how capable the model is. Each layer is independent, so a failure in one is caught by the next, and the dangerous action has to defeat all four to do real harm.

Allowlists and Denylists
#

The piece that earns its keep every single day is the command allowlist. The kind of list matters more than the exact syntax, which varies by tool, so think of it as two lists. One list holds the safe, reversible commands the agent runs constantly, which it should execute without ever stopping to ask. The other holds the destructive commands, which should always stop for confirmation.

# run these without asking, they are safe and reversible
allow:
  - status and diff commands
  - running the test suite
  - running the linter
  - staging changes locally
# always stop and ask first, these are hard to undo
deny:
  - pushing to a remote
  - hard resets and history rewrites
  - recursive force deletes
  - dropping or truncating tables
  - deleting or updating rows

What matters is not the specific entries, but that the safe path runs without interruption and the destructive path is gated by default rather than by my memory. I should never be the thing standing between an eager agent and a dropped table, because I will eventually be tired or distracted at exactly the wrong moment. The list makes the safe behavior automatic and the dangerous behavior require a deliberate yes.

This is also where the asymmetry of data work shows up most clearly. A destructive command takes a second to execute and its recovery can take hours, or may not be possible at all. The denylist exists to put a human pause in front of precisely those actions, the ones where the time to cause harm and the time to repair it are wildly out of balance. Everything reversible runs free. Only the irreversible has to wait for me.

Setup That Pays Back Forever
#

It would be easy to read all of this and see a wall of obstacles, while in practice it is the opposite. Almost every guardrail here is one-time setup that pays back forever. The editor configuration, the branch rules, the read-only role, and the short gate list are written once and then they simply hold. They do not cry wolf, because they only interrupt me for the rare action that is genuinely hard to undo, and the constant reversible work that fills most of my day never touches a single one of them.

A read-only database role is the clearest example of the trade. It takes a few minutes to create and it removes an entire category of accident permanently.

create role ai_agent_readonly;
grant usage on warehouse dev_wh to role ai_agent_readonly;
grant usage on database analytics_dev to role ai_agent_readonly;
grant usage on all schemas in database analytics_dev to role ai_agent_readonly;
grant select on all tables in database analytics_dev to role ai_agent_readonly;
-- intentionally no insert, update, delete, or grants, and no production access

There is one detail worth adding. These grants apply only to the tables that exist when you run them, so a table created later will not be readable until you also grant read access on future tables in the database. It is a small, one-time addition, and it does not change the safety of the role, which still cannot write anything.

With a role like that, the worst case for a runaway query is a slow read, not a deleted table. That is the whole philosophy in one object. A few minutes of setup converts a catastrophic failure mode into a minor annoyance. If I could only keep one guardrail, it would be this one, because command and branch mistakes are usually recoverable while a destructive write against real data often is not. Remove the worst outcome first, then layer the rest on top.

Putting It Into Practice
#

  1. Reframe every guardrail decision as whether the agent can do the harmful thing, not whether you trust it not to.
  2. Start each session read-only, granting write and execute access deliberately rather than by default.
  3. Protect the shared branch at the platform level, and let the agent commit but never push.
  4. Allowlist the safe, reversible commands and deny the destructive ones, so the safe path runs without interruption.
  5. Give the agent a read-only role pointed away from production, and treat this as the single most important guardrail.
  6. Keep a short human-gate list for genuinely irreversible actions, and read the real diff before approving any of them.
  7. Invest the one-time setup once, and let configuration hold the line on the days your discipline cannot.

Related