Generative AI · AI Agents

Designing an AI agent that asks before it acts

By Abhinav R··2 min read

Building an agent that can “do anything” is easy to demo and hard to trust. With AgentOS AI I wanted the opposite: an agent whose every possible action I can list on one page, and that does nothing until a person approves the plan.

The workflow

You describe a goal in plain English and give it some public URLs. AgentOS turns that into a plan with three steps: read the pages, build a CSV from what it found, and prepare an email draft summarising it. You review the plan, approve it, and only then does it run. Each step's inputs, outputs and status are saved, so you can see exactly what happened.

Decision 1: a closed tool registry

The agent can only use three tools: research_public_pages, generate_csv and prepare_email_draft. They are defined as a fixed list in the schema, so a plan that names any other tool fails validation before it reaches the engine. There is no shell tool, no “run this Python” tool, and the email tool never sends anything. It only writes a local draft.

If the model can't name a dangerous tool, it can't use one.

Decision 2: the plan is checked, then approved

When an OpenAI-compatible model is configured, it writes the plan as JSON. Without one, a deterministic planner produces the same three-step workflow. Either way the output goes through the same Pydantic validation. The research step may only visit the URLs you supplied. A run is created with approved=False, and the engine refuses to start any run that hasn't been approved.

Decision 3: web pages are data, not instructions

A page the agent reads could contain text like “ignore your instructions and…”. So retrieved text never goes back into tool selection; it only flows into the CSV and the draft. The URL reader also blocks local hostnames and private IP addresses (to reduce SSRF risk), re-checks redirects, and caps request time and response size.

A small bug class I didn't expect: CSV injection

If a scraped page title starts with =, +, - or @, a spreadsheet may run it as a formula when you open the CSV. AgentOS prefixes those cells so they open as plain text. My first version missed cells with leading whitespace, like " =1+1", which some spreadsheet apps still evaluate, so I added a test for exactly that case.

What it doesn't do (yet)

What I took away

Most of the safety came from what I didn't build. Limiting the tools, validating every plan and keeping a human approval step made the agent less flexible but easy to reason about, and that trade-off is what I would want before letting an agent touch real systems. The stack is FastAPI, SQLAlchemy and a React/Vite canvas, with tests for the planner, URL policy, approval gate and CSV neutralisation running in CI.

This post is based on one of my projects. You can read the full case study or the code: