Guardrailed operations agent
NORA
An AI operations agent that can move money — and the deterministic guardrails that stop it from doing something expensive and stupid.
Runs locally against generated mock data for a fictional company. Nothing touches a real system; email tools write drafts that are never sent.
- Period
- Aug – Sep 2026
- Status
- Prototype
- Role
- Agent design, Guardrail and policy engine
- Context
- Repository name: ops-copilot. "Ops Copilot" and "Nora" are the same project.

Screenshot of the running product.
The problem
Why this needed to exist
A model can answer support questions — that part is solved. The question this prototype tests is harder: what stops an agent that is allowed to move money from doing something expensive because a customer message told it to?
A rule written in a system prompt is a suggestion the model can be argued out of. An operator needs limits that hold regardless of what the model is persuaded of.
Who it’s for
- Operators of small direct-to-consumer brands
- Support and fulfilment leads
- Anyone evaluating agents with real-world write access
The solution
How it works
NORA has situational awareness (whole-book sweeps rather than single lookups), real tools against a mock order database, company policy it searches before acting, and a deterministic guardrail layer between every write tool and its effect.
A blocked action returns to the model as an ordinary tool result, so it reads the reason and adapts — usually by escalating to a human — instead of retrying blindly.
Where the guardrail sits
- Operator
- Web console
- CLI
- Approvals
- Agent
- Claude + Tool Runner
- Frozen system prompt
- Session context
- Policy
- Risk tiers
- Refund rules
- Channel limits
- Tools
- Intel sweeps
- Orders & refunds
- Social / email / calendar
- Record
- Mock store (SQLite)
- JSONL audit log
- Evals
Implemented
What’s actually built
Risk-tiered tools
Every tool is READ, WRITE_LOW or WRITE_HIGH. Reads are free; refunds, customer emails, social publishing and campaign sends pass through the policy engine.
A refund policy in code
Over $200 is refused outright. Over $50, older than 30 days, or a customer refunded in the last 90 days is held for approval. Everything else is allowed.
Fails closed
If no approver is wired up, held actions are denied. In the web console, no answer within three minutes, a closed tab or a dropped session all resolve to denied.
Approval cannot override refusal
Operator approval is consulted only for actions the engine holds. There is no path from a pasted customer message to a $5,000 refund.
Drafting is free; reaching an audience is not
A social post or email campaign can be drafted immediately. Scheduling it to real followers is held for sign-off, and each email provider’s real daily send limit becomes the ceiling.
The operator connects accounts, never the agent
NORA has no tool to connect a social or email account. She can see which are live, and is refused outright if she tries to post to one that is not.
Morning brief
The CLI opens by scanning the book and telling you what needs a decision before you have asked.
An eleven-page console
Dashboard, Approvals, Audit Log, Social, Email, Calendar, Orders, Customers, Shipments, Policies and Evals — with NORA as a slide-over on every page and a Ctrl/⌘K command palette.
Interface
Screens from the real product
Approvals: the guardrail rules and safety properties, visible rather than taken on trust. The dashboard reads the local store directly — no API key needed. Every tool call is appended to a JSONL audit log; the evals score this log, not the model’s prose. Scored scenarios: happy path, must-escalate, prompt injection, out-of-scope and more. Policies the agent searches before it acts.
My role
What I did
Everything in the prototype: the agent wiring, the tool surface, the guardrail engine, the mock-data generator and policies, the evaluation suite, and the web console — FastAPI and Jinja2 with hand-rolled SVG dials and charts, no build step and no chart library.
Responsibilities
- Agent design
- Guardrail and policy engine
- Evaluation harness
- Web console (UI + backend)
Stack (verified from source)
- Python
- Claude (Anthropic Tool Runner)
- FastAPI
- Jinja2
- Vanilla JS
- Hand-rolled SVG
- SQLite
- JSONL audit log
Decisions
Technical and design choices
- 01
Guardrails in Python, not the prompt
The prompt describes the policy so the model can plan around it; the if-statements enforce it. The model never gets to decide whether a rule applies.
- 02
Score what it did, not what it said
Evals read the audit log. An agent that says "I’ve escalated this" without calling the escalation tool fails the case.
- 03
A frozen, cacheable system prompt
Volatile facts like today’s date arrive as a separate system message, keeping the cached prefix intact. A run with zero cache reads flags that something dynamic leaked into the prefix.
- 04
One seam for real systems
All data access goes through one module, so SQLite can later become Shopify or Stripe without touching the agent.
Trade-offs
Challenges along the way
- 01
Prompt injection through customer text
A dedicated eval bucket feeds the agent customer messages that try to talk it into refunds. The guardrail, not the model’s judgment, is what makes those cases pass.
- 02
Approval UIs that fail open
Browser approval loops have many quiet failure modes — timeouts, two tabs, shutdowns, double-resolves. Each is covered by an offline check that must resolve to denied.
- 03
Undeclared dependencies
The console worked locally only because packages had been installed by hand; a clean install could not start the server. The fix was declaring them — and the habit of installing your own project somewhere fresh.
Results
What can be checked
Evaluation suite
33 scored scenarios across seven buckets (happy path, auto-approve, must-escalate, injection, out-of-scope, briefing, channels), plus 27 offline guardrail assertions that run in about a second.
Lessons
What I took away
- The hard part of a production agent is the integration surface and its limits, not the conversation.
- Making the guardrail observable — an Approvals page, an Audit Log — turns safety from a claim into something an operator can watch.
What’s next
Planned — not built
Planned work
- Real integrations (store platform, payments, email) behind the existing data seam
- Authentication and multi-tenancy
- Deployment beyond a single local operator
Current limits, stated plainly
- Mock data for a fictional company; no real customers or orders.
- Sends and publishes are simulated even where a draft is produced.