Local AI agent design
An agent that writes files is one more user account.
The real problem
A tool-using agent is not a chatbot with buttons. The moment it can read a file, call an API or execute code, it becomes a non-human user account — with rights, a memory, and no intuition for what is dangerous.
Most deployments handle this in the system prompt: "do not run destructive commands". A prompt is not access control. It is bypassed by phrasing, poisoned through memory, and leaves no auditable trace.
How I solve it
I build the ReAct loop around three separations that do hold:
- Tools classified by effect, not by name. Anything that writes goes through explicit approval — the user sees the action before it leaves.
- Confined execution. Model-produced code runs in a sandbox: network cut, writes bounded to a throwaway directory, reads of SSH keys and keychains denied. A probe tests the jail before each run.
- Paths resolved, not concatenated. Nine write sinks go through symlink-resistant resolution bounded to declared roots.
A trap learned in the field
On my own agent, write/read classification was done on the tool name. English verbs were covered. French verbs — generer, supprimer — were not: they fell into the read bucket and slipped through without validation.
The lesson is not "I forgot French". It is structural: a pattern list is a sieve by construction. Classification now happens at tool registration, through a mandatory field — a tool with no declared effect does not register.
What it delivers, measured
- 44 native tools + 18 MCP servers in production
- 119 MCP tools exposed out of 188 catalogued — the gap is a choice, not an oversight
- 2,061 tests on the agent alone
- Outbound mail gated behind a read-only flag
Where it runs in production
- KlodyAI — Coding agent · ReAct
- Assistant proactif — Observe → propose loop
- Klody Core — Control plane
Your data cannot leave the building?
That is precisely the problem I solve. A 30-minute call is enough to scope an audit.