Quilzomanual

Limits that hold: what a hijacked AI agent still cannot do

The declaration is enforced by code outside the model, so it holds however the model is persuaded.

In the adminAgents

Prompt injection is text an agent reads that tells it to do something its user did not ask for. No classifier reliably tells those words from honest content. Quilzo does not try to: it limits what a run can do, records what it read, and stops for a person when private material and somebody else's words meet an outbound call.

Decide what it can reach

Every field of the declaration narrows the agent. Leave one out and the agent has less, not more.

FieldLimits
capabilitiesThe operations it may use: read_page, write_page, search_pages and the rest. The model picks from this list and cannot add to it.
retrieval.refWhether it reads the live site (the default) or the draft, which nobody outside has seen.
retrieval.types, locales, pathOnly pages of these content types, in these languages, under this part of the site.
toolsTools on outside systems, each on exactly one host with a stated purpose. There are no wildcards. Tools are reached through integrations a person approved (see Tools and the MCP gateway).
delegatesFor a supervisor, the agents it may hand work to. Each runs as the intersection of both declarations, on what is left of the supervisor's budget.
ask_firstThe capabilities and tools that stop the run for a person.
autonomypropose, draft or publish: the most it may ever do. A model reaches it only by passing evaluations.

A run is also bounded by the person who starts it. Somebody with only read access who runs an agent that may write gets a run that cannot write, and the run says which capabilities it lost and why.

Set a budget it cannot argue with

Every agent has a budget, and a declaration without one is refused. One run may use at most:

"budget": { "steps": 25, "tool_calls": 15, "duration": "10m0s", "tokens": 40000, "money": "0.50" }

Money is counted at each model route's own prices, in the gateway's currency. Across runs, the model gateway caps each caller by the minute, the day and the month, and an agent is charged against its own line:

quilzo gateway budget agent:returns-editor --money-per-day 5.00 --money-per-month 60.00

An agent talked into a loop stops at its limit. See Models and the gateway for routes and prices.

Know what it read

A run records everything it read, by page, listing, tool and delegate. Reading content that somebody else could have written marks the run, and anything it produced then needs a person before it is relied on or published. The run's page and its receipt both list what it read.

Text from a page, a tool or a delegate reaches the model inside a fence marked as untrusted content, with characters a person could not see taken out first. The fence tells the model what is data. The limits above are what hold if it is persuaded anyway.

The exfiltration breaker

Three things together let an agent leak data: it holds something private, it has read something somebody else wrote, and it can send something outside. Each alone is ordinary. Together, the words somebody else wrote can tell it to take what is private and send it.

So when a call would complete all three, the run stops and a person sees exactly what it read, what is private about it, and where the call would go. Private material includes the unpublished draft, memory it recalled, personal data a tool returned, and what a delegate read privately. An outbound call is a call to a tool or a program's connection to a host. A program cannot wait for a person, so for a program the call is refused, with the reason.

The breaker does not inspect what is in the call, which would make it the classifier it exists to avoid. It is deliberately coarse: a run that should send private material out is approved once, by a person who has seen why it stopped.

Ask whether it could, before it does

quilzo agent could answers whether a run of an agent could do something, and why. It asks the same code the run uses, so the answer is not a second opinion:

quilzo agent could --model returns-editor write_page returns
yes  returns-editor could write_page returns, decided by a model, started by dana
  then: a person approves the exact call first
  then: what it read was written by somebody, so a person decides before anything it produced goes live
quilzo agent could help-desk write_page returns
no  help-desk could write_page returns, decided by walking its declaration, started by dana
  help-desk: write_page refused "write_page" is not in this agent's capabilities (list_pages, read_page, search_pages, similar_pages)

Ask about a tool with tool:NAME, a host with host:NAME, a run somebody else would start with --as PERSON, and an agent's own program with --program. For apps connected over MCP, quilzo apps could CONNECTION OP [PAGE] answers the same question about one connection.

The gate as a service

quilzo agent probe takes a declaration and a list of calls as JSON, and answers each one. Use it in CI to check a declaration before it is merged, or from another system to ask what an agent would be allowed to do:

{
  "manifest": {
    "name": "support-bot", "kind": "retrieval",
    "purpose": "Answer customers from published help pages",
    "capabilities": ["read_page", "search_pages"],
    "autonomy": "propose",
    "budget": { "steps": 8, "tool_calls": 4, "duration": "2m" }
  },
  "calls": [
    { "op": "read_page", "ref": "live", "page": "returns" },
    { "op": "write_page", "ref": "draft", "page": "returns" },
    { "op": "publish" }
  ]
}
quilzo agent probe < question.json
{
  "agent": "support-bot",
  "answers": [
    { "op": "read_page", "allowed": true },
    { "op": "write_page", "allowed": false,
      "reason": "support-bot: write_page refused \"write_page\" is not in this agent's capabilities (read_page, search_pages)" },
    { "op": "publish", "allowed": false,
      "reason": "support-bot: publish refused \"publish\" is not in this agent's capabilities (read_page, search_pages)" }
  ],
  "allowed": 1,
  "refused": 2,
  "tainted": true
}

A second model that reviews each action

Name a model route as the reviewer, and every action an agent's model chooses is shown to it before it runs:

quilzo config set agent.reviewer ROUTE

The reviewer sees the goal a person set and the action chosen, and nothing of what the agent read, so nothing a page planted can reach it. It can let the action through or stop it; a stopped action waits for a person on the run's page, and Let it go ahead performs exactly that action. A reviewer that cannot be reached stops the run. It costs one more model call per action, and it is the last defence, not the only one: the declaration, the breaker and asking first come before it.

Desktop apps, and your own desktop (experimental)

An agent can work a desktop app in a desktop cell: a Firecracker or Cloud Hypervisor microVM, restored from a warm snapshot you build with the app inside, worked through its accessibility tree the way the browser is worked through a page. Presses that commit to something wait for a person, Enter always does, and typing into a cell is under the exfiltration breaker. One cell runs at a time. The image, with its apps and the helper inside it, is yours to build, and the microVM runs as Quilzo's user without Firecracker's jailer, which is why cells are experimental. quilzo cell status says whether this machine can run one; the settings are cell.backend, cell.binary, cell.snapshot, cell.memory and cell.vsock.

quilzo desktop consent asks your desktop's own dialog for your keyboard and pointer and gives the session straight back. No run may use your desktop.

The watchdog, and the shield

Asking and accepting no is how an agent should behave. Reaching again and again for what it was never given is not. quilzo agents lists what each model and app has been doing and which are not accepting refusals. When one crosses the line, the watchdog flags it, the agent loses the autonomy its evaluations earned, and the shield's agent-misbehaving playbook tells the security contact and whoever answers for the agent, and opens a case.

An agent caught following a planted instruction is treated more firmly: the agent-steered playbook pauses it for 24 hours and tells people, so it does not run until somebody narrows what it may do. You can pause one by hand:

quilzo shield pause returns-editor --for 24h --reason "kept trying to publish"

Every protection the shield applies ends by itself, and quilzo shield lift ends one early.

Next