Controlled runtime

The controlled runtime is the environment the agent server builds from the account's configuration and runs every agent in. It decides what an agent can reach, how much an agent may do, and where an agent's data may go. This page is the summary; each control has its own page.

The agent is fixed

An agent is a definition: written by a developer, validated by a real run before it is published, versioned, and unchanged while it runs. A person, a chat bot or an assistant chooses which agent runs. The definition decides what runs.

What an expression can reach

The Python expressions in a definition run with the account's allowlist in place of Python's builtins. A function, class or module is available to an expression only when the allowlist names it, and a module comes without the modules it imports. Besides the allowlist, an expression sees the variables of its own function, the agent's variables, the conversation's variables, and the sys, command, result and exc names. See Python expressions.

Search2o Cloud checks every expression when the agent is validated and refuses the constructs that lead out of the agent's data: import, names and attributes that start with an underscore, lambda, the walrus operator, calling the result of an expression, and the others listed under Compile rules. Each Python operator is allowed, denied or rewritten to a function of the account's own.

What an agent cannot see

Credentials stay out of the definition. A secret is read as sys.secret['NAME'], with the name written out, and the agent server resolves it at run time; the definition shows which secrets an agent uses, never their values. See Secret vault.

An agent's variables belong to that agent. The one channel between agents is the conversation: a conv variable set by one agent can be read by the next agent in the same conversation, by design. See Variables and namespaces.

Where an agent's calls can go

APIs, databases, MCP servers and LLMs are reached through profiles, which administrators define and share across the account. An api command calls an API profile, so the hosts an agent can reach are the ones set in the profiles. Every HTTP call goes through a connection pool that administrators size.

How much an agent may do

The runtime limits bound a run: how long an agent may run, how many times a loop may iterate, how many rows a database call may return, how much an agent may spend on LLM calls, and how long a definition may be. A run past its time limit ends with the result code timedOut; a loop past its limit fails the run. The limits apply to every agent in the account.

The runtime bounds what an expression may do, not how much work one line of Python does. An expression runs on the agent server alongside every other run, so a very long computation delays the other runs. Two controls cover this:

  • Operator rewriting. The account can map an operator to a function of its own, so that a ** b runs as bounded_pow(a, b) and a very large power is refused before it is computed. See Compile rules.
  • Isolating the agent server. The agent server is a stateless process, so it can run inside whatever isolation your organization uses: a container with processor and memory limits, a separate host, a restricted account. See Agent servers.

The same runtime on every agent server

Every agent server builds its runtime from the same configuration, so an agent behaves the same wherever it runs. A change to the configuration, the profiles or the allowlist reaches every agent server and is live on the next run. An agent that is already running keeps the runtime it started with until it finishes. See Agent runtime.

What leaves the agent server

Search2o Cloud receives the search request and the conversation state, and the state is encrypted before it leaves the agent server. API, database, MCP and LLM traffic goes where the profiles point. Everything else an agent handles — API responses, database rows, credentials, variables — stays on the agent server for the life of the run. See Data privacy.

When something fails

An expression that raises an error stops its command, and the message names the command's path and the Python error. An onError block on the command or the function can handle the error instead. Every run, with its result, its duration and its LLM cost, is recorded in the reports.