Allowlist

The allowlist is the complete set of names that an agent's Python expressions may use. Expressions do not get Python's builtins; the allowlist takes their place. A name that is not on the allowlist does not exist for an agent, and an expression that uses it is refused before the agent ever runs. The allowlist applies to every agent in the account, and developers edit it in the UI under Guardrails.

How expressions are contained

Expressions are contained at the application level, not by the operating system. Four things decide what an expression may do. The allowlist decides which names it can reach. The compile rules decide which operators and which shapes of expression are accepted. The runtime limits cap a run in time, iterations, rows and LLM spend. The scope rules below decide which variables are visible. The runtime does not limit memory or CPU; rewriting an operator to a function of your own is the tool for operations that could load the agent server.

a Python expression in bracesallowlistthe only names it can reach; public members of allowlisted objects; no import, no dunderscompile ruleseach operator allowed, denied or rewritten to a function of your ownruntime limitstime, loop iterations, database rows, definition size, LLM spendscopeearlier locals, agent./conv. variables, sys and command namespaces — nothing else
What decides what an expression may do

One entry per line

Each line names one thing to allow. Blank lines are ignored, and anything after a # is a comment, so comments can group a long allowlist into sections.

# Text handling
json.loads
json.dumps
re.sub              # replace matches in a string

What an entry can be

There are six forms. The last column shows how an agent writes it in an expression.

FormExampleUsed as
A Python builtinlenlen(items)
A builtin typestrstr(5)
One method of a builtin typestr.joinstr.join('-', parts)
One name from a modulemath.sqrtmath.sqrt(16)
A whole modulemathmath.sqrt(16)
Everything public in a modulemath.*sqrt(16)

A module inside a package is named in full: urllib.parse, xml.etree.ElementTree.

The same forms allow your own code. mycompany.pricing.discount is resolved the same way as math.sqrt, as long as the package is installed beside the agent server.

Renaming an entry with as

Any entry can be given the name that expressions will use.

math.sqrt as sqrt                # sqrt(16)
datetime.datetime as datetime    # datetime(2026, 1, 2)

Without as, an expression uses the entry as written: math.sqrt is used as math.sqrt(16).

An entry that ends in .* cannot be renamed, because that form brings in many names at once. An as on such a line is refused when the allowlist is saved.

Choosing between the forms

Naming one function is the narrowest choice. math.sqrt allows that function and nothing else in the module.

Allowing a whole module is convenient when agents use many of its functions. It allows every public function in the module, so know what is in the module first.

The .* form puts the names into the expression directly, without the module in front. It also replaces any earlier entry of the same name: math.* provides a pow, so a pow entry higher up the list is no longer Python's pow. Use one of the other forms unless short names are required.

What a name gives an agent

An entry allows the name itself and the public members of the object behind it.

A class brings its methods with it. An entry of str allows str.join and str.split without an entry for either. The same is true of dict, list and the other builtin types.

An allowlisted class can be used to construct an object, and the public members of that object can be used.

A module does not open the modules it uses

A module entry allows what is in that module, not the modules it imports.

Python modules import each other freely. The json module imports codecs, and uuid imports os. Without this rule, allowing json would quietly allow codecs.open, and allowing uuid would allow the operating system.

json                # json.dumps and json.loads are allowed
                    # json.codecs is refused

The same holds for a package. Allowing urllib does not allow urllib.parse. Name urllib.parse when that is what agents need.

What is always refused

Any name that starts with an underscore is refused: private names and dunder names, whether a variable, an attribute, a function or a keyword argument, and on an allowlisted object too.

format and format_map are refused on every object. A format string is read when the expression runs, so it can reach places that are checked nowhere else. Use an f-string instead.

import is not available in an expression. Everything an agent can reach is named in the allowlist.

The rules for what an expression may contain, beyond names, are listed in Compile rules.

Scope of an expression

An expression may reference only:

  • the names on the allowlist, with the public members of the objects behind them;
  • variables set earlier in the same function, and the function's arguments;
  • agent and conversation variables set earlier, as agent.x and conv.x;
  • the read-only sys, const and command namespaces. Which sys variables are present is decided in System variables.

See Namespaces.

Functions must not block

Expressions run on the agent server's shared event loop. A function that blocks that loop holds up every agent on the agent server, so such a function does not belong on the allowlist. time.sleep and synchronous network calls are examples.

Async functions are allowed. When the whole expression is a call to an async function, the result is awaited for you. Inside a larger expression, use await; see Awaiting.

When an entry is wrong

Every entry is resolved when the allowlist is saved, on the agent server behind the UI. If any line fails, the allowlist is not saved, and each failing line is reported with its own message.

nosuchmodule       Could not be imported.
math.nope          Could not be imported.
math.* as m        A star import cannot be renamed with 'as'.

The line is reported exactly as it was written, so a long allowlist shows which rows to fix.

Once the allowlist is saved, every agent server rebuilds its names before its next agent run. No restart is needed; see How a change reaches every agent server.

Each agent server resolves each entry in its own Python environment. An entry that cannot be imported on one agent server is skipped there, with a message in that agent server's log, and the rest of the allowlist still loads. A package installed on one agent server and missing on another shows up this way, so keep the environments of your agent servers the same.

Your own code

Install the package on every agent server and name the function in the allowlist. A function that a Python operator is rewritten to must be on the allowlist, and it must take the two values that operator works on. Code that the agent server itself calls, such as an LLM adapter, a vault function or an encryption key function, is not an allowlist entry; it is named on the Hooks page. See Hooks.

FieldTypeDefaultDescription
allowlistlist of stringWhat agent expressions may call. These run on the server's shared event loop and must not block it - asyncio.run, for example. A coroutine is awaited only when it is the whole expression, not when it appears inside a larger one.