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

This capability is engaged in

AuditBuild

Your data cannot leave the building?

That is precisely the problem I solve. A 30-minute call is enough to scope an audit.