Blog

I loop AI agents on my repos. Here's an easy way to see what they push.

Running coding agents in a loop is fast and genuinely fun. The hard part: seeing what they actually push, and stopping the occasional bad push before it lands. Why hooks and branch protection were not enough, and what I built instead.

Running coding agents in a loop is one of the better things to happen to my workflow this year. Write a task, let an agent (or three) run, come back to working code. It is fast, and it is genuinely fun.

The part that took me longer to sort out was not the looping. It was this: once you have a few agents pushing to a repo, sometimes unattended, you want an easy way to see what they actually landed, and ideally a way to stop the occasional bad push before it reaches your real git host. Not because the agents are reckless. Because loops move fast, and “fast and unattended” is exactly when a clean record and a safety net are worth having.

I tried the obvious things first. Here is why they did not do the job, and what I built instead.

The obvious fixes don’t bind an agent

First instinct: a pre-commit hook. Scan for secrets, block force-pushes, the usual. The problem is where it runs. A pre-commit hook executes in the same environment the agent controls. The agent can pass --no-verify, edit the hook, or just not call it. A guard that runs inside the loop is a suggestion to the loop, not a constraint on it.

Second instinct: branch protection on the host. Better, because it lives where the agent cannot reach it. But branch protection governs who can push to which branch. It does not read the contents of a push. It will not notice a committed API key, a private key, an rm -rf of a protected path, or a migration that drops a column. It answers “who pushed where,” not “what is in this push.”

So the two easy options each miss in a different way. The hook sees the content but the agent can skip it. Branch protection cannot be skipped but is blind to the content.

The check has to live outside the loop’s reach

What I actually wanted had two properties:

  1. It runs somewhere the agent cannot touch - not in the agent’s environment, not as a step the agent invokes.
  2. It holds the only credential to my real git host - if the agent never has the upstream token, it cannot push around the check.

Put those together and the shape falls out: a gate that sits between the agent and the real host, holds the credential, and inspects every push before deciding whether to forward it.

How nimblegate does it

Your machine, or your agents, push to the gateway over SSH on a key. The gateway is the only thing that holds the upstream credential. It checks the push against the rules you turned on. A clean push is relayed to your real host (GitHub, Gitea, GitLab) byte-for-byte: same commit SHA, author, signature. An unsafe push is held, with a report saying exactly what tripped and where.

Because it sits on the push path and holds the credential, there is no “skip the check.” The only route to your real repo is through it.

Out of the box it flags the things loops actually generate: hardcoded credentials, private keys, force-push to protected branches, rm -rf of protected paths, migration and schema drift, plus a set of web and cloud rules. You can add your own regex rules from the dashboard.

Every decision lands in a feed: accept or reject, per repo, with the findings. This is the part I use most. When a few agents have been looping overnight, I can scroll the feed in the morning and see exactly what they tried to push and what got held, without reading every diff by hand. That is the “easy way to see what is landing” I wanted in the first place.

And when a push is rejected, the gateway posts a structured comment on the PR and fires a webhook with the same JSON. The agent reads why it failed and fixes itself, then pushes again. So the gate is not just a wall at the end of the loop. It becomes a step inside the loop: write code, push, get told what is wrong, fix, repeat - with guardrails so a stuck agent does not hammer forever.

What it is not

nimblegate is one layer, not a sandbox. It checks the deterministic rules you configure, on the push path. It does not stop an agent from doing damage inside its own environment, it is not a replacement for code review, and it does not claim to catch everything: it catches what you tell it to, the same way every time. The value is a consistent, unskippable checkpoint between your loops and your real repo, plus a record of what happened. Keep the rest of your security posture in place.

Try it

There is a live, read-only demo with sample data, nothing to install: demo.nimblegate.com. The source and a getting-started guide are on GitHub: github.com/nimblegate/nimblegate. It is self-hosted, one container, and source-available (free for non-commercial use).

I have been running it on my own repos for a few months and I am building the rest in public. If you loop agents on your code, I would like to know what would make this genuinely useful to you, and where you think the gaps are.

← All posts · nimblegate is a self-hosted push gateway for AI agents - how it works · live demo