Building Guardrails for AI Coding Agents
How TradersPost rebuilt agent documentation, quality gates, and parallel worktrees so AI coding agents can ship safely without burning context or bypassing review.
Founder / CEO
Bottom Line
- AI agents fail when documentation is too large to load, checks are too broad to run, or environments collide with each other.
- We moved from dumping thousands of tokens of agent docs into every prompt to on-demand pattern tools that load only the relevant slice.
- File-scoped quality gates, mutation testing, and complexity checks make “tests passed” mean something for agent-written code.
- Parallel agents need isolated worktrees with shared infrastructure, not a shared checkout fighting over the same branch and containers.
- The operating model is explicit: humans own outcomes; agents are leverage, not authority.
Like a lot of engineering teams, we started using AI coding agents because the leverage was obvious. An agent that can navigate a large Symfony codebase, write tests, and open a draft pull request is useful. An agent that confidently ships the wrong migration, skips the hard verification steps, or tramples another session’s working tree is expensive.
This post is about the guardrails we built so agents could work inside TradersPost’s real development workflow (the same workflow humans use) without turning the repository into a pile of unreviewed automation. It is not a product pitch for AI trading, and it is not a claim that agents replace engineering judgment. Our company posture is blunt: do not blindly trust agents. Humans own outcomes.
The first problem was not model quality
Our early agent setup had a quieter failure mode than bad code generation. It was context waste.
We had consolidated a lot of project knowledge into agent instruction files. That sounded responsible. In practice, hooks and prompts kept injecting large documentation blobs into every session. Agents spent tokens rereading rules they did not need for the task at hand, then still missed the specialized pattern for the change they were about to make.
The rewrite that stuck was architectural, not rhetorical. We split monolithic backend and frontend guidance into focused pattern documents, then exposed them through structured project tools an agent can call on demand. Instead of loading everything up front, an agent working on an entity asks for the entities pattern. An agent touching Twig asks for the template and component patterns. Checklists became callable too: new entity, new controller, migration safety, compliance review.
That change did two things at once. It reduced the default prompt tax, and it made the correct next document the path of least resistance. Agents are opportunistic. If the right instruction is one tool call away and the wrong shortcut is a full-tree lint command, they will take the tool call, if you design for that.
Quality gates had to become file-scoped
The second failure mode was verification theater.
A monorepo with large test suites invites a bad habit: run everything, or run nothing useful. Agents are especially prone to it. Faced with uncertainty, they either launch an expensive full suite or declare victory after a narrow command that does not cover the changed lines.
We standardized on targeted checks while iterating, and branch-diff gates before review. The practical interface is a single file-aware command that can run formatting, static analysis, complexity, mapped tests, patch coverage, and mutation testing for the paths you actually touched. Agents are steered toward “check these files” rather than “boil the ocean.”
Two gates mattered more than the rest for agent-written code.
Mutation testing
Line coverage answers whether code executed. It does not answer whether the test would notice a broken assertion. Mutation testing flips the question: change the production code slightly and see whether the suite fails.
We added Infection scoped to changed lines, with a hard requirement that covered mutants are killed. Full-repository mutation runs are refused: the mutant surface is far too large to be a useful local gate. The point is not to generate a vanity score. The point is to stop merges where an agent wrote a test that calls the code and never checks the outcome.
Complexity and nesting ratchets
Agents can produce working code that is locally clever and globally unmaintainable. Cyclomatic complexity and nesting depth are imperfect metrics, but they are useful as a design signal when enforced on changed code.
We calibrate against the repository’s own distribution rather than an industry slogan. Soft and hard thresholds catch new density without forcing a rewrite of every legacy method on day one. Existing hotspots are grandfathered into a baseline that we prune down over time. New or worsened findings fail the gate. That combination matters for agents: they cannot “fix” a complex method by shoving complexity into a nearby private method and calling it done, because the changed-file scope still sees the mess.
Parallel agents need real isolation
Once multiple agents were useful, the next collision was physical: shared checkouts, shared PHP containers, shared databases, and shared queues. Two agents on one working tree is not a process problem. It is a filesystem and runtime problem.
We built worktree support so each agent (or human reviewer) gets a sibling git worktree with its own application container and isolated application state, while still sharing the heavy local data plane that is expensive to duplicate. Creation is a first-class Make workflow, not a tribal script. Reviewing someone else’s pull request is the same mechanism: create a review worktree, open that folder, work only there.
The lesson was less about git worktrees themselves and more about treating agent concurrency as an environment design problem. If isolation is optional, agents will share. If isolation is the default path with working URLs and quality gates, parallel work becomes routine instead of heroic.
Verification tooling had to speak both human and agent
Documentation alone does not keep agents honest. The feedback loop has to be machine-readable and local.
We invested in tools that answer the questions agents otherwise invent:
- What calls what? Static call-graph analysis for callers, callees, and pull request impact, useful before a risky rename and before a human review.
- Where did the time go? Runtime profiling that can attach to tests, console commands, or requests, then compare refs without turning every investigation into a one-off spreadsheet.
- Did the UI actually render? Local browser smoke commands that open a real route on the current worktree and produce a screenshot an agent is expected to look at, not merely a green exit code.
None of these replace judgment. They replace guesswork. An agent that can name the callers of a changed method, prove the hot path got faster or at least not slower, and show the page still renders is an agent you can review. An agent that only pastes “tests passed” is not.
What we refuse to automate away
Some things stay human on purpose.
Trade execution and money paths still prioritize correctness over speed of change. Database migrations follow expand / migrate / contract sequencing, with a separate safety checker that fails deterministic hazards before merge. Broker abstraction changes still need paper or low-risk live verification where applicable. Compliance boundaries (independent traders, user-owned accounts, no cross-account control) are enforced as product policy, not as optional copy guidance.
We also learned that automated AI review is not free. A noisy review bot that floods a pull request can waste more attention than it saves. Durable review instructions and deterministic gates beat a always-on commentary firehose. When the automation is wrong, turn it off. Keep the standards.
What improved
After the on-demand documentation split, agents stopped paying a large fixed documentation tax on every prompt and started loading the pattern that matched the task. After file-scoped gates and mutation/complexity requirements, “green” became harder to fake. After worktrees, parallel agents stopped colliding on the main checkout as a matter of course.
The cultural change mattered as much as the tooling. Agents are part of the development system now, which means the development system had to become explicit: which docs to load, which checks to run, which environment to use, and which decisions still require a person.
Lessons
- Design for opportunistic agents. If the correct workflow is harder than the shortcut, the shortcut wins.
- Scope verification to the change. Full-suite default behavior trains agents to either waste time or skip substance.
- Measure assertions, not just execution. Mutation testing catches the hollow tests agents love to write.
- Treat complexity as a merge gate on new work. Baselined legacy debt is fine; new density is not.
- Isolate parallel work at the environment layer. Prompt instructions will not fix a shared working tree.
- Keep humans accountable. Tools can make agents safer. They cannot own the production outcome.
If you are adopting coding agents on a real production codebase, start with the boring infrastructure: small retrievable docs, deterministic local gates, isolated workspaces, and an explicit rule that agents propose while humans dispose. The model will keep changing. The need for guardrails will not.