Jeff Kent Buenaflor.
All articles

Guardrails for agents that run while I sleep

Topic
Agent safety
Published
October 2026
Reading time
5 min

An agent that runs without me shouldn’t do damage while I’m away. It also shouldn’t stop and wait for me for no reason. I’ve hit both. These are the guardrails I use on my long-running AI agents, each with the reason behind it.

Prompt rules weren’t enough. An agent can read a rule, agree with it, and break it later once its context compacts, which means the system shortens the agent’s memory of the conversation. So most of what follows is code that runs before or after the agent acts.

Stopping the waits

One guardrail is a hook, a small script that runs at a fixed point in the agent’s work. Claude Code can run a check before each tool call, and I put one on every agent. It refuses two kinds of command.

The first is a directory change joined to another command (cd somewhere && ...). That shape triggers a permission prompt, and an agent sitting on a prompt does nothing until a human notices. The second is a long foreground sleep, where the agent does nothing but wait. I audited one day of agent work. Foreground sleeps cost about 121 minutes of agent time, and calls that ran until the tool’s time limit cost about 1,462 minutes. The hook stops the sleeps, and the long calls now run in the background.

Foreground sleeps cost about 121 agent minutes a day and calls at the tool time limit about 1,462.

The hook has false positives. The text sleep 60 inside a commit message trips it, for example. Each one costs a single retry, and I accepted that.

Every brief that lets an agent run commands also carries one clause. Use the dedicated tools and absolute paths, never run a command that asks for approval, and if a blocked command is truly needed, stop and report it. If I find an agent waiting on a prompt, I stop it and restart it with a better brief. Nobody approves from the agent’s screen.

Watching the burn rate

Agent accounts have a usage limit that resets after a fixed window. A plain level check shows how full an account is now, so it looks healthy until the last moments before the limit. It does not show how fast the account fills. So a watcher reads each account’s burn rate, which is how fast usage grows.

When an account nears its limit, a hook holds every new helper agent and workflow. Running steps finish. Agents on an account at its limit wait for the reset or move to an account with room. The guard fails open on purpose, so if the guard itself goes down it never stops the team.

Breaking my own guards

A guard that passes proves nothing. A guard that fails when you break the thing it protects proves it works, so I break each one once before I trust it.

This caught real defects. A detector for stale jobs reported green when its own lookup failed, so it went quiet exactly when it could not see anything. The fix was a third exit code. Each check now has three results: found a problem, found nothing, or could not run. “Found nothing” and “could not run” never share an exit code.

Each check returns found a problem, found nothing or could not run.

Scheduled jobs can fail with no trace too. If the folder for a job’s log doesn’t exist, the shell can’t open the log file and the job never starts. No log, no error. After a move to a new machine, some probes died this way, silently.

Rules about claims and reviews

An agent can report a problem in one environment as if it belonged to another. So every finding and every action names its environment. A result from the test environment never carries over to production, or the other way around, and a check that failed or returned nothing gets reported as unchecked, not as passed.

A builder never reviews its own work. Each code change gets an independent reviewer agent, and the reviewer approves one exact version, so if the change moves, the approval doesn’t move with it. Every reviewer runs on the strongest model. On changes that touch sensitive areas such as sign-in, infrastructure or security, the reviewer checks the server path with extra care and names what it didn’t verify.

Before anything leaves the building there’s a privacy check. Agents write pull request text, tickets and documents that other people read, and before any of it is posted a script scans the final text for local paths, machine names and internal setup details. Once, the checker refused every automated review comment. The cause was in the data the comment was built from, not in the rendered text, so the fix went into that data.

Cleaning up after themselves

Long-running agents start dev servers, tunnels and file watchers, and then they forget them. Left alone, these processes pile up on a machine until memory runs short. So each agent runs an orphan check at the end of each job and before handover. It stops its own orphans, and any old orphan it finds, by exact process ID.

All of these run as code, and each came from an incident that I wrote down next to the rule so the next agent knows why it exists. They also keep my gate small. Each one removes a reason for an agent to stop and ask me, so the questions that do reach me are about production and business decisions.

More on the system these guardrails protect is in Where I still stand in an agent team.

Email hello@jeffkent.dev to talk about running agents safely.

Want this for your team?

Send a short note about the project. I reply within one working day.