How do you make a check hold on every path an agent takes?

On this page3 sections
An agent can reach a PNR by many paths, but every one of them passes through the operating system. That is where OnRails holds the agent, so no path goes around the PNR.
Previously in this series, we saw that putting AI agents into production takes both predictability and flexibility. Predictability never needed a predefined path, only checks that can’t be skipped. Those checks sit at the points of no return, or PNRs: actions that can’t easily be undone, such as applying a payment in the ERP. OnRails holds the agent at each PNR until its checks pass.
That left the harder part. An agent that plans its own steps can reach one PNR by many paths. It might use a tool it was given, a script it wrote, or a call straight to the ERP. A hold that sees only some of those paths leaves the PNR open. So where should the hold live?
To answer that, we first need to know what those paths have in common. Each of them comes down to programs running on a machine. And no program can read a file, start another program or open a connection on its own. It has to ask the operating system’s kernel, through a system call.
An agent can use any number of tools and write any number of scripts, but an operating system has only so many system calls. Every path the agent takes passes through them. Engineers call a layer like this a “narrow waist.”
What is a narrow waist?
The term comes from networking. The internet carries every kind of application over every kind of network, and all of them meet at one protocol in between, IP. Drawn as layers, that design looks like an hourglass, with IP at its narrow waist.
An agent’s machine has a narrow waist too. Above it sit the tools, scripts and harnesses the agent might use, and below it the files, programs and connections they reach. The system calls sit in between, and that’s where OnRails holds the agent. A rule enforced there applies alike to everything above it, since the kernel sees processes, not tools or frameworks.
Is seeing every path enough?
A sandbox, such as a container, already works at the narrow waist, and it sees every path. But it decides each action on its own: whether the agent may read this file or reach that host. A PNR, though, depends on what happened before the action, such as whether the check passed on the latest invoice matches. The kernel shows each action as it happens, and keeps no record of what came before.
OnRails keeps that context itself, through information-flow control. Data carries a taint from its source, and the taint follows the data as it moves. A program that reads a file takes on the file’s taint, and a file it writes takes on the program’s. OnRails also keeps track of which program ran and which files changed after each check. So if a script the agent wrote changes the invoice matches after the check passed, OnRails knows the pass no longer counts. It holds the agent at the PNR until the check passes again.
Why not the prompt, a tool hook or a proxy?
Those are where teams put business rules today, and they are a good start. But each one misses something. The model weighs a prompt against everything else it reads, and even a strong one is sometimes confidently wrong. A tool hook sees the command that runs a script, not what the script goes on to do. A proxy on the network sees each request leave, not which program sent it or what that program read first. A hold at the narrow waist sees every path, and OnRails remembers what happened on each one.
That puts the business rules in the system around the agent, not in the model. Holding the agent at its PNRs is only the start of what that system can do.
So what are we working toward? That’s where the last part of this series picks up.
