Guardrails for an AI agent that edits your app
I built an in-app design agent for a payments codebase. Most of the work went into what it is not allowed to do, enforced in code rather than in the prompt.
Our designers wanted to change the product directly instead of handing over screenshots and waiting. So I built Lumen: a small chat window that lives inside the running app in development, drives a coding agent, and turns a designer’s request into a real code change.
Giving an AI agent write access to a payments codebase is the kind of idea that should make you nervous. The interesting part of the project wasn’t the chat. It was the leash.
Prompts are not guardrails
The first instinct is to write rules into the system prompt: “never read secrets”, “never push to main”. Those rules help the agent behave well, but they aren’t enforcement. Prompts can be misread, overridden or talked around. Anything that truly must not happen has to be blocked by code the agent can’t change.
The four guards
- A secret guard. A hook runs before every tool call and refuses anything that touches environment files, keys, certificates, SSH config, package registry tokens or secrets folders. It doesn’t matter how the request is phrased; the tool call simply fails.
- A tool allowlist. The agent can read and edit files and run a few safe commands: lint, build,
git status,git diff. Nothing else. - Pull requests only. Publishing commits to a
design/…branch and opens a pull request. Protected branches such as main, develop and production are never pushed to directly, so an engineer always reviews the change. - A production build check. The agent only exists in development. A build step scans the production output for a marker string and fails the build if any agent code slipped through.
Here’s a re-enactment of those rules. It’s scripted, so no model is running, but the outcomes match what the real guards do:
Design agent · simulated
Tool calls
- None yet.
Context makes it useful
Safety makes it acceptable; context makes it good. A designer can click an element in the running app, and the agent receives that element’s React component stack, so “make this button quieter” points at the right file. The agent also gets the current route and a project rules file that describes the design system, so its changes look like ours.
What I’d keep
- Enforce in code, guide in the prompt. Use the prompt for taste and the code for rules.
- Review is the real safety net. Pull requests turn an agent’s output into a normal change that a person approves.
- Make the safe path the easy path. Designers never had to remember the rules, because the tool only allowed the safe ones.