Generative AI · AI Agents
Designing an AI agent that asks before it acts
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)
- There are no user accounts. It is a single-user local tool and shouldn't be exposed to an untrusted network.
- Runs execute in-process, so restarting the server interrupts a run. Production would need a durable queue.
- The URL checks reduce SSRF risk but don't replace network-level egress controls; DNS rebinding is still possible.
- Pause, cancel, retry and a full audit log are on the to-do list.
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: