Billing tickets answered end to end, with a person on every refund.
Your business rule
“A refund needs a person’s sign-off.”
- Answers the ticket
- Refund without asking held
- You sign off
- Sends the refund
Onboard AI agents like new hires: give them the goal and your business rules, not a plan for every case.
Instructions
instructions.md
Customer payments
Alone
Check, advice only: “Apply payments only after the matches balance.” advice only
Sign-off, advice only: “A write-off needs a person’s sign-off.” advice only
Rules
onrails.yaml
version: 2policy: | agent = program "claude" rule apply-after-check: with AGENT block tool "cashapp" arg "apply" unless tool "match-check" exited 0 since the last write "**/matches.csv" because "Apply payments only after the matches balance." rule write-off-sign-off: with AGENT ask tool "cashapp" arg "write-off" because "A write-off needs a person's sign-off."Drafted by OnRails, reviewed and turned on by you.
Run
Without OnRails: Receipt says paid. $1,200 short.
With OnRails: Checked, applied, $1,200 kept open.
The agent plans the steps. You mark its points of no return, and OnRails holds the agent at each one until your checks pass.
Your business rule
“A refund needs a person’s sign-off.”
Your business rule
“Customer records never go to a site we haven’t approved.”
Your business rule
“Deploy only after the tests pass on the latest change.”
Your business rule
“A memo goes to a client only after an LLM judge approves it.”
A rule on your customer records follows them into any program your agent runs. When one is refused, the agent reads why, so it can take a path the rule allows.
Your business rule “Customer records never go to a site we haven’t approved.”
/data/customers/ , which carries the CUSTOMERS taintrenewals.csv , which carries the CUSTOMERS taintA list the agent makes from your customer records carries their taint too.
curl -T renewals.csv https://bashupload.com/renewals.csv , which carries the CUSTOMERS taint: refusedpython3 share.py , which carries the CUSTOMERS taint: refusedmake share , which carries the CUSTOMERS taint: refusedcurl -n -T renewals.csv https://partners.acme.com/upload/ , which carries the CUSTOMERS taint: let throughEvery program runs in your sandbox and meets the operating system at its system calls, where OnRails checks it.
Checked by OnRails, with eBPF in the Linux kernel.
Every refusal, the business rule behind it, and what the agent did next, across your workflows.
Agent runs
1,240
5 workflows
Refused, with a reason
23
After a refusal, the agent
Tue 6:47 pm Releases
This refusal, step by step
Latest refusals
Tue 6:47 pm Releases
deploy-after-tests-pass
took the allowed path
Tue 2:36 pm Customer payments
apply-after-check
took the allowed path
Tue 11:20 am Partner renewals
customer-records-stay-inside
took the allowed path
Tue 10:05 am Client memos
judge-before-send
didn’t try again
Workflows 5 workflows, 1,240 runs in the last 7 days
| Workflow | Runs | Refusals | Last run |
|---|---|---|---|
| Customer payments Finance | 58 | 6 | Tue 6:20 pm |
| Billing tickets Support | 268 | 3 | Tue 5:12 pm |
| Partner renewals Sales | 174 | 4 | Tue 4:46 pm |
| Releases Engineering | 486 | 9 | Tue 7:31 pm |
| Client memos Legal | 254 | 1 | Tue 6:08 pm |
| All workflows | 1,240 | 23 |
Refusals 23 in the last 7 days, newest first
| When | Rule, and the reason the agent read | What the agent did next |
|---|---|---|
| Tue 6:47 pmReleases | deploy-after-tests-pass “The code changed after the last passing test run. Run pytest, then deploy.” | took the allowed path ran pytest, then deploy |
| Tue 2:36 pmCustomer payments | apply-after-check “Apply payments only after the matches balance.” | took the allowed path ran match-check, then cashapp |
| Tue 11:20 amPartner renewals | customer-records-stay-inside “Customer records go only to hosts we approve. Share them through the partner portal.” | took the allowed path sent it through the partner portal |
| Tue 10:05 amClient memos | judge-before-send “Send a memo only after memo-judge approves its latest draft. Run memo-judge, then send.” | didn’t try again |
| Mon 4:12 pmReleases | deploy-after-tests-pass “The code changed after the last passing test run. Run pytest, then deploy.” | took the allowed path ran pytest, then deploy |
The latest 5 of 23
Rules 7 rules across 5 workflows
| Rule | Workflow | Status | Fired | Last fired |
|---|---|---|---|---|
| apply-after-check | Customer payments | On | 6 | Tue 2:36 pm |
| write-off-sign-off | Customer payments | On | 0 | none |
| refund-sign-off | Billing tickets | On | 3 | Mon 3:47 pm |
| customer-records-stay-inside | Partner renewals | On | 4 | Tue 11:20 am |
| deploy-after-tests-pass | Releases | On | 9 | Tue 6:47 pm |
| judge-before-send | Client memos | On | 1 | Tue 10:05 am |
| cite-before-send | Client memos | Flag only | 2 | Mon 4:18 pm |
A flag-only rule says what it would refuse, and refuses nothing.
No change to your agent’s code, whichever SDK you build on.
OnRails keeps your business rules firm on every run, so your team can put more workflows into production without designing every step in advance.
Dependable agents come from the system they run in, not just the prompt. We’re building OnRails so your agents can adapt while your business rules hold firm.
Swapnil GandhiStanford CS PhD
Faye TengWharton MBA
Prof. Christos KozyrakisStanford CS
Prof. Mendel RosenblumStanford CS