Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.maadify.com/llms.txt

Use this file to discover all available pages before exploring further.

The Code execution tool lets an agent run a small Python script inside a sandbox during a workflow. Use it when a task needs deterministic computation that the language model is not good at on its own — parsing or reshaping JSON, regex extraction, math and aggregation, sorting and deduplicating, joining results from several tools, or validating tool inputs and outputs before sending them on. Code execution tools are configured from connectors as a Code execution tool. After you configure the tool, add it to a sub-agent or parent agent workflow. When the workflow runs, Maadify validates the script, executes it in an isolated sandbox, and returns the result, captured stdout, and the list of available linked tools to the agent.
Code execution tool configuration with default code and include files toggle

How code execution works

A code execution tool has three parts:
  • Default code is an optional Python script that runs when the agent does not provide its own.
  • Default inputs are JSON values exposed as variables inside the script.
  • Linked tools are other Maadify tools that the script can call by name.
At runtime, Maadify merges the agent’s request with any saved defaults, parses the Python code, runs it in a sandboxed interpreter with strict resource limits, and returns the value of the last expression as the tool output. Anything the script writes with print is captured separately as stdout.
Diagram of agent input, default inputs, linked tools, attached files, sandbox execution, and returned output

Create a code execution tool

1

Open the code execution connector

Go to Connectors and open the Code execution connector.
2

Create a Code execution tool

Add a tool with the type Code execution tool. The tool configuration opens with the script editor and the default inputs JSON field.
3

Describe the tool

Add a clear name and description that explains when an agent should use this code execution tool. The description shows up in the tool picker and helps the agent decide when to call it.
4

Add default code (optional)

Use the Default code editor to provide a script that runs when the agent calls the tool without supplying its own code. Leave it empty to require the agent to write the code each time.
5

Add default inputs (optional)

In Default inputs, paste a JSON object whose keys become variables in the script. Use this to share constants, lookup tables, or shared configuration with every run.
6

Enable attached files (optional)

Turn on Include attached files if the script should be able to read files the user attaches in chat. See Attached files in the sandbox.
7

Link other tools (optional)

Link other Maadify tools so the script can call them. See Calling other tools from a script.
8

Save the tool

Save the configuration. Maadify validates the default code, stores the inputs, and updates the tool input schema.

Use code execution in an agent

1

Open the agent configuration

Open the parent agent or sub-agent that should run scripts.
2

Add the code execution tool

Choose the code execution tool you created from the connector.
3

Choose how the agent can use it

For assistant sub-agents, register the tool so the agent can call it. For execution-focused parent agent steps, configure the tool as an executable action with a fixed payload.
4

Update the system prompt

Add a section to the sub-agent prompt that explains when to use code execution and what the sandbox supports. Reference the code_execution_stubs and input.files template variables so the prompt always reflects the current linked tools and attached files. See Prompt template variables.
5

Test in chat

Open https://app.maadify.com/chat, choose the agent, and send a request that should trigger a script run.
Adding a Code execution tool to a sub-agent
If you are adding a code execution tool to a sub-agent, you will need to add the tool to the sub-agent’s system prompt. Use the system Code Execution Template as it provides all necessary stubs and limitations.

What the agent sends to the tool

When the agent calls the code execution tool, it sends:
  • code: a complete Python script. The value of the last expression is returned as the tool output.
  • inputs: an optional JSON object. Each key is exposed as a top-level variable in the script.
Maadify merges any default inputs you saved with the agent’s inputs before the script runs. The agent can also read context from the workflow, such as previous tool outputs or runtime inputs, by populating those values into the inputs object.

What the tool returns

A successful run returns:
  • success: true.
  • output: the value of the last expression in the script.
  • stdout: anything the script printed.
  • available_functions: the list of linked tools the script could have called.
A failed run returns:
  • success: false.
  • error: an object with type (such as SyntaxError, TypingError, RuntimeError, or ToolValidationError) and a message.
  • stdout: any output captured before the failure.
Encourage the agent to read the error.message and rewrite the script before retrying. Retrying the same code unchanged will fail the same way.

Sandbox capabilities and limits

Scripts run inside a restricted Python interpreter, not a full Python process. Many features and libraries are intentionally unavailable.

Importable modules

Only the following standard library modules are available. Importing anything else raises ModuleNotFoundError.
  • json
  • math
  • re
  • pathlib
  • typing
  • os
  • sys
  • asyncio
  • datetime (the module imports, but datetime.now() and date.today() are not available — pass the current time in through inputs if you need it)
There is no requests, numpy, pandas, pydantic, csv, collections, itertools, functools, dataclasses, enum, decimal, uuid, hashlib, base64, random, time, urllib, subprocess, socket, or threading in the sandbox.

Available builtins

print, len, range, min, max, sum, sorted, reversed, zip, enumerate, map, filter, any, all, round, abs, divmod, ord, chr, hex, bin, oct, bool, int, float, str, list, tuple, dict, set, repr, iter, next, id, hash, isinstance, hasattr, and type.

Builtins that are not available

open, exec, eval, compile, __import__, globals, locals, dir, vars, input, format, callable, frozenset, bytearray, and the bytes([...]) constructor.

Syntax that is not supported

The sandbox parser rejects:
  • class definitions of any kind, including dataclasses, TypedDict, NamedTuple, and custom exception subclasses. Re-raise built-in exceptions such as ValueError instead.
  • with statements and context managers. Read and write files directly with pathlib.Path methods.
  • yield and generators. Use list comprehensions, map, or filter.
  • match and case statements. Use if and elif.
  • % string formatting and str.format(). Use f-strings.

Syntax that works

f-strings, list and dict and set comprehensions, lambdas, decorators, type hints, async and await, try and except and raise and raise from, the walrus operator :=, ternary expressions, and * and ** unpacking.

Resource limits

Each run is bounded by per-call limits. Defaults are roughly:
  • Wall time: 5 seconds.
  • Memory: 128 MB.
  • Allocations: 100,000.
  • Recursion depth: 50.
Platform caps allow up to 15 seconds, 256 MB, 250,000 allocations, and recursion depth 100. Scripts that exceed any limit are killed with a runtime error.
Code execution is not a place for long-running jobs, web scraping, or work that needs network access. Use a connector or a browser tool for those tasks.

Attached files in the sandbox

When Include attached files is enabled, files the user attaches in chat are mounted into the sandbox under /files/ and a list named files is automatically added to the script’s variables. Each entry has the shape:
{"path": "/files/<name>", "file_name": str, "file_type": str, "element_id": str}
Read the files with pathlib.Path. The open(...) builtin is not available.
from pathlib import Path

results = []
for f in files:
    file_type = f.get("file_type") or ""
    if file_type.startswith("text/") or file_type == "application/json":
        content = Path(f["path"]).read_text()
    else:
        content = Path(f["path"]).read_bytes()
    results.append({"name": f["file_name"], "size": len(content)})

results
Always iterate the runtime files list and read f["path"] instead of hard-coding /files/<file_name>. When two attachments share the same name, Maadify suffixes the path automatically and the display name will not match.
Files exist only in the sandbox’s in-memory virtual filesystem. The script cannot reach the host filesystem, and nothing the script writes is persisted after the run.

Calling other tools from a script

A code execution tool can link to other Maadify tools so the script can call them as Python functions. Use this to combine tool outputs without making the agent call each tool one at a time.
1

Link tools

In the code execution tool configuration, link the Maadify tools the script should be able to call.
2

Call them with await

Inside the script, call each tool with a single dict as input_data and await the result.
result = await some_linked_tool({"field": "value"})
Linked tools are exposed under their original tool name. When several linked tools share the same base name, Maadify also exposes the unique <tool_name>_<id> form so the script can target a specific instance.
Always pass the payload as a single dict. Do not spread it with **payload — the sandbox rejects that pattern and you will see a TypingError.
Code execution tools cannot link to other code execution tools. This prevents recursive sandbox runs.

Prompt template variables

Two prompt template variables help an agent use the code execution tool well. Reference both from the sub-agent system prompt so the prompt always reflects what is actually wired into the tool.

code_execution_stubs

code_execution_stubs is a dictionary keyed by the unique tool name (for example code_execution_tool_42). Each value is a Python stub block that lists every linked tool’s signature. Loop over the dictionary and render each stub:
{% if code_execution_stubs %}
{% for tool_key, stub in code_execution_stubs.items() %}
### Stubs for `{{ tool_key }}`
```python
{{ stub }}
```
{% endfor %}
{% endif %}
This keeps the prompt accurate as you link or unlink tools. The agent learns the exact function names, expected payload fields, and return types without you maintaining a parallel description by hand.

input.files

input.files is the list of files attached to the current chat turn. Each entry has element_id, file_name, and file_type. The list is populated whether or not Include attached files is enabled, so the prompt can describe what was attached even when the script does not have read access.
{% if input.files %}
The user attached {{ input.files|length }} file{{ 's' if input.files|length != 1 else '' }}:

{% for f in input.files %}
- `{{ f.file_name or f.element_id }}`{% if f.file_type %}{{ f.file_type }}{% endif %}
{% endfor %}
{% endif %}
Use both variables together. The code_execution_stubs block teaches the agent which linked tools it can call. The input.files block tells the agent which files are available to read in the sandbox.

Best practices

  • Pass data into the script through inputs instead of hard-coding it in code. Hard-coded data wastes tokens and breaks when the input shape changes.
  • Make sure the last line of the script is the value you want returned. An assignment on the last line returns nothing.
  • Prefer returning structured data, such as dicts or lists of primitives, over pretty-printed strings. Later workflow steps can map structured fields directly.
  • Use print for diagnostic logs only. The structured output is what the rest of the workflow consumes.
  • Keep loops bounded and avoid deep recursion so the script stays within the resource limits.
  • When an attached file is large, read its size with Path(...).stat().st_size before reading the bytes.
  • Test the tool in chat with realistic inputs before adding it to a production workflow.

Troubleshooting

  • The sandbox only ships the modules listed in Importable modules.
  • Replace third-party libraries with built-in equivalents — for example, use re instead of regex helpers, or use json instead of a parser library.
  • If you need a network call, use a different connector instead of code execution.
  • The sandbox parser does not support class, with, yield, or match statements.
  • Refactor classes into plain functions and dictionaries. Replace with open(...) with pathlib.Path reads. Replace generators with list comprehensions. Replace match with if and elif.
  • Check that the last line of the script is the value you want returned, not an assignment.
  • The tool returns the value of the last expression. result = compute() returns nothing because it is a statement, not an expression. Add a final line result to return it.
  • The linked tool was called without await. Add await to the call.
  • Linked tools are async and must be awaited from within the script.
  • Pass the payload as a single dict, for example await tool_name({"field": "value"}).
  • Do not spread the payload with **payload — the sandbox rejects this pattern.
  • Confirm Include attached files is enabled on the code execution tool.
  • Use pathlib.Path rather than open(...), which is not available in the sandbox.
  • Iterate the runtime files list and read f["path"] rather than guessing /files/<file_name>.
  • The run hit a resource limit. Check the error message for details on which limit was exceeded.
  • Reduce the size of the data you pass in, bound any loops, or move heavy work into a different connector.