> ## Documentation Index
> Fetch the complete documentation index at: https://docs.genesiscomputing.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Code Executor Tools

> Execute Python code securely in isolated environments with access to data sources, libraries, and file systems for dynamic data analysis and automation.

## **Overview**

### **Tool Name**

```json theme={null}
code_executor_tools
```

### **Purpose**

The **code\_executor\_tools** enable secure execution of Python code within Genesis Data Agents. Run dynamic calculations, data transformations, API integrations, and custom logic without pre-defined functions. Perfect for ad-hoc analysis, prototyping, data science workflows, and extending agent capabilities with custom code on-the-fly.

#### **Functions Available**

1. **`execute_python_code`**: *Run Python locally or on Snowflake Snowpark. For local execution, assign the final value to the `result` variable.*
2. **`create_env`**: *Create a named managed environment for local or Snowpark execution.*
3. **`list_envs`**: *List available managed environments.*
4. **`list_env_deps`**: *Inspect the packages installed in one managed environment.*
5. **`update_env`**: *Add or remove packages from an existing managed environment.*
6. **`delete_env`**: *Delete a managed environment after explicit confirmation.*
7. **`run_repo_script`**: *Run a server-pinned Python `required_check` for the active Blueprint phase and record platform-owned evidence.*

### Key Features

<Steps>
  <Step title="Secure Execution" icon="shield-check">
    Run code in isolated sandbox with resource limits and security constraints to prevent system abuse.
  </Step>

  <Step title="Rich Library Access" icon="books">
    Standard/runtime libraries are available immediately, but local execution should not assume third-party packages are already installed. Use managed environments when you need extra dependencies.
  </Step>

  <Step title="Data Source Integration" icon="database">
    Direct access to configured databases, file systems, and APIs within executed code.
  </Step>

  <Step title="File System Access" icon="folder-open">
    Read and write files to Git repositories and storage locations from within executed code.
  </Step>

  <Step title="Vault Secret Injection" icon="key">
    Collect credentials with `get_web_content(action="ask_user_for_secret")` and pass the returned vault names in `secrets` so values are injected as `SECRET_<NAME>` environment variables.
  </Step>

  <Step title="Dynamic Variables" icon="code">
    Pass variables into code execution and retrieve results for further processing.
  </Step>

  <Step title="Error Handling" icon="triangle-exclamation">
    Comprehensive error messages with stack traces for debugging failed executions.
  </Step>
</Steps>

<Note>
  Genesis injects `bot_id`, `thread_id`, and `user_id` automatically for
  `execute_python_code`. The parameter tables on this page list only the
  user-supplied fields.
</Note>

## Managed local environments

When `execute_python_code` runs with the local executor, do not assume
third-party packages are preinstalled. Use the managed environment tools to
install and reuse dependencies outside the running code.

On container deployments where Genesis runs as root with the `cortex_sandbox`
user, named local environments are stored under
`<GIT_PATH>/.genesis_runtime/python_envs`, rather than bot storage. Genesis
migrates existing environments to this folder at startup. The environments
remain readable and runnable by sandboxed code, but only the root-owned server
can write them. On these deployments, keep the mounted Git workspace persistent;
see [Genesis on Docker — volume mounts](/docs/deployments/Docker/Genesis-Container-Distribution#volume-mounts).

| Tool | Purpose | Parameters |
| - | - | - |
| `create_env` | Create a named environment before the first local run. | `name` (`string`, required), `deps` (`string[]`, optional), `executor` (`"local"` or `"snowpark"`, default `"local"`) |
| `list_envs` | List reusable environments available to the executor. | `executor` (`"local"` or `"snowpark"`, default `"local"`) |
| `list_env_deps` | Inspect the packages installed in one environment. | `venv` (`string`, required), `executor` (`"local"` or `"snowpark"`, default `"local"`) |
| `update_env` | Add or remove packages after the environment already exists. | `name` (`string`, required), `add_packages` (`string[]`, optional), `remove_packages` (`string[]`, optional), `description` (`string`, optional), `executor` (`"local"` or `"snowpark"`, default `"local"`) |
| `delete_env` | Remove an environment when it is no longer needed. | `name` (`string`, required), `confirm` (`boolean`, default `false`), `confirmed` (`boolean`, default `false`), `executor` (`"local"` or `"snowpark"`, default `"local"`) |
| `execute_python_code` | Run code inside the same named environment. | `code` (`string`) or `script_path` (`string`), `function_name` (`string`, optional; `script_path` only), `args` (`object`, optional; requires `function_name` and `script_path`), `env` (`string`, optional), `timeout` (`integer`, default `10` for local execution), `executor` (`"local"` or `"snowpark"`, default `"local"`), `connection_id` (`string`, optional, Snowpark only; default `"Snowflake"`) |

Each local run leads its own process session. When code exits, times out, or is
cancelled, Genesis stops the processes it left running in that session so they
do not outlive the run.
On Linux, Genesis also stops descendants that detach from the session with
`setsid` or a double fork, when those operations are available to the run. On
macOS, a process that leaves the session with `setsid` can outlive the run.

The local executor is unavailable when the Genesis server runs on Windows. In
that case, `execute_python_code(executor="local")` returns
`success: false`, `unsupported_platform: true`, and an error explaining that
its sandboxed child process requires POSIX file-descriptor passing and process
controls. Use a Genesis server running on macOS or Linux, or select
`executor="snowpark"` with a configured Snowflake connection.

<Tip>
  Reuse the same environment name across the full workflow: `create_env`,
  `list_env_deps`, `update_env`, then `execute_python_code(..., env=...)`.
  Local environment names are normalized before they are stored, so spaces
  become hyphens, uppercase characters become lowercase, and repeated
  separators collapse to a single hyphen.
</Tip>

## `run_repo_script`

Use `run_repo_script` when the active Blueprint phase declares a
`required_check` exit criterion. The platform resolves the check's script path
and SHA-256 from the server-owned snapshot captured when the mission started,
refuses execution if the repository bytes do not match that hash, and records
the observed exit code as durable provenance for the phase gate.

| Parameter | Type | Default | Description |
| - | - | - | - |
| `check_name` | `string` | required | Name of the `required_check` declared by the active Blueprint phase. |

Local Python execution treats `sys.exit()` and `sys.exit(0)` as clean
completion. For `run_repo_script`, Genesis reports `success: true` when the
observed exit code matches the phase's expected code, including a matching
non-zero code. See [required check exit criteria](/docs/Blueprint/Blueprint-Branching#required-check-exit-criteria)
for how to configure that code.

The script runs with a scratch working directory. Read mission files through
the `GENESIS_MISSION_REPO_PATH` environment variable, which contains the
mission repository's absolute path. The script must be a valid UTF-8 Python
file from that repository and is limited to 256 KB. Genesis applies the same
safety judges used by local `execute_python_code` when required, runs the
verified bytes, and records the result consumed by `EXIT_PHASE`.
The script also receives `GENESIS_CHECK_NAME`, set to the check name from the
active phase snapshot. Imports of installed packages remain allowed. A check may
also import a blueprint-declared, hash-pinned utility library by its declared
name; Genesis verifies and safety-reviews its source on each run and serves the
verified source from memory. Changes to that library refuse the check. Other
imports that resolve to Python code in the mission repository or scratch area
remain refused because that code is not covered by a pin. See [Shared libraries
for required checks](/docs/Blueprint/Blueprint-Branching#shared-libraries-for-required-checks)
for how to declare libraries from the mission repository or a registered managed
source at a pinned commit.

For local required-check execution, a phase that captured entry context also
provides `REQUIRED_CHECK_CONTEXT` from `genesis`. It is a read-only snapshot with
`blueprint_inputs`, `mission_thread_id`, and `phase_entered_at`; nested objects
are immutable too. It is `None` when the active check has no captured context.
The context is supplied by the server, not by code-execution arguments or
environment variables. Snowpark execution does not provide this local-check
context.

```python theme={null}
run_repo_script(check_name="validate_repository")
```

This operation reads the pinned script and any declared libraries, may make
safety-judge LLM calls for them, executes Python, and writes a provenance record.
Each library adds one source read and, if it passes static scanning, one auxiliary
LLM judge call per run. Writing a result file does not complete a `required_check`.

<Note>
  For `executor="local"`, keep the submitted entry point inline with `code=...`.
  `script_path` is rejected, and local code must not read source files or load,
  import, compile, or execute code from local files. Native `open()` may read
  task-owned documents and data in the task's own repository or scratch area
  under `BOT_GIT_PATH`, `BOT_REPOS_PATH`, or `BOT_SCRATCH_PATH`; source-code
  files remain disallowed. Other threads' uploads, environment, credential, or
  secret files, and `.git` internals are also disallowed regardless of file
  suffix. Local preflight still rejects obvious sandbox-escape, host-probing,
  and native/FFI bridge patterns.
  Local execution runs in a fixed subprocess child runner with
  `BOT_SCRATCH_PATH` as the working directory and temp root. Import workspace
  roots with `from genesis import BOT_GIT_PATH, BOT_REPOS_PATH,
      BOT_SCRATCH_PATH, sanitize_path` to read or write permitted task files under
  those roots (including the repo working tree at `BOT_REPOS_PATH`). Genesis
  also copies a managed `child_runner.py` into scratch before each run. Use
  `executor="snowpark"` when you need file-backed code execution.

  Local preflight checks Python syntax and AST structure rather than matching
  policy terms in raw text. This avoids rejecting comments, ordinary prose
  strings, regular-expression patterns, or unrelated attribute calls for rules
  aimed at executable constructs. The scan resolves module-scope aliases and
  direct function rebindings before classification, so restricted calls remain
  blocked when reached through imports or aliases; forbidden-module imports are
  rejected in any scope. When a construct is rejected, `safety_guidance`
  identifies its `blocked_rule`, the `matched_code`, and `matched_line`; code
  that does not parse is rejected with `block_reason_code: "syntax_error"`.
  Safety-judge denials also include a fixed, actionable `safety_guidance.reason`
  selected by denial category, rather than the judge's free-form explanation.

  Snowpark requires a live Snowflake connection. On SQLite-metadata deployments
  (`SNOWFLAKE_METADATA=FALSE`), Snowpark calls that resolve to the default
  `connection_id="Snowflake"` fail fast with `error_code:
      STAGE_REQUIRES_SNOWFLAKE_CONNECTION` before opening a session — add a saved
  Snowflake connection and pass its id, or use `executor="local"`. When an
  administrator has hidden the virtual System `Snowflake` connection, Snowpark
  calls that target it return `success: false` with `type: connection_disabled`;
  use a user-created Snowflake connection instead.

  When stage setup fails because the Snowflake session has no current database,
  Snowpark returns `error_code: CONNECTION_DATABASE_UNAVAILABLE` with the
  configured database and schema from the connection. Fix the connection's
  database/schema in **Config → Connections**, grant the role `USAGE` on that
  database, or pass a different `connection_id`.

  See [Snowflake attribution](/docs/Integrations/Data%20Sources/Snowflake/Snowflake#identify-twin-scanner-queries).
</Note>

<Note>
  When a request or returned error mentions `boto3`, AWS SDK work,
  EKS/Kubernetes, Helm, `kubectl`, AWS CLI, cloud deployment, or cloud
  monitoring, `execute_python_code` can return `agent_reminders`,
  `sandbox_tools_recommended`, and `sandbox_tools_reference` to steer the task
  toward `sandbox_action` on a remote backend such as `eks` or `k8s` instead
  of retrying inside the Genesis application container.
</Note>

```python theme={null}
create_env(
    name="synth-gen",
    deps=["faker>=20.0.0", "pandas>=2.0.0", "numpy>=1.24.0"],
)

list_env_deps(venv="synth-gen")

execute_python_code(
    code="import faker, pandas, numpy; result = 'ok'",
    env="synth-gen",
)

update_env(
    name="synth-gen",
    add_packages=["pyarrow>=14.0.0"],
)
```

## Genesis SDK in local execution

When the local executor injects runtime credentials, inline Python can import
the governed `genesis_sdk` client instead of reaching into backend internals:

<Note>
  `genesis_sdk` ships inside the Genesis runtime image at `/app/genesis_sdk`
  (it is not a PyPI package). Do **not** call
  `create_env(deps=['genesis-sdk'])`, `create_env(deps=['genesis_sdk'])`,
  `update_env(add_packages=['genesis-sdk'])`, or
  `update_env(add_packages=['genesis_sdk'])` — the similarly named public
  PyPI package is unrelated and will not satisfy
  `from genesis_sdk import Genesis`. If the import fails on a deployed
  Genesis runtime, treat it as a deployment/packaging regression and file a
  CLI ticket rather than attempting to install a workaround.
</Note>

```python theme={null}
from genesis_sdk import Genesis

gx = Genesis.from_environment()
gx.progress.message("Starting query")

rows = gx.query.rows(
    connection_id="snowflake.prod",
    sql="select region, sum(revenue) as revenue from sales group by region",
    max_rows=1000,
)

gx.artifacts.write_json("outputs/regions.json", rows)
gx.progress.complete("query")
result = {"row_count": len(rows), "artifact": "outputs/regions.json"}
```

`Genesis.from_environment()` reads `GENESIS_API_BASE_URL` plus either
`GENESIS_RUNTIME_TOKEN` (managed local execution) or `GENESIS_API_TOKEN`
(external PAT mode).

Inline `code` executes as a plain module from top to bottom. Its returned value
is the top-level `result` variable. `function_name` and `args` are only valid
with `script_path`; passing either with inline `code` is rejected. To invoke a
function from inline code, call it in the module and assign the result yourself.
For a custom-scanner launcher, the active scan session id is available as
`from genesis import scan_id`; outside a scan launcher, `scan_id` is `None`.

Prefer these SDK surfaces before a generic tool bridge:

* `gx.capabilities()`
* `gx.query.rows(...)` and `gx.query.df(...)`
* `gx.tools.list()`, `gx.tools.schema(name)`, and `gx.tools.call(name, args)`
* `gx.artifacts.write_text(...)`, `write_json(...)`, `write_csv(...)`, `write_bytes(...)`, `read_text(...)`, `read_json(...)`, `read_bytes(...)`, `list(...)`, `exists(...)`, and `delete(...)`
* `gx.progress.message(...)`, `update(...)`, `complete(...)`, `fail(...)`, and `artifact(...)`

<Note>
  For binary artifacts (zip, image, parquet, sqlite, etc.), prefer
  `gx.artifacts.write_bytes` and `read_bytes`, which handle bytes natively. If
  you must move binary content through the `file` tool via
  `gx.tools.call("file", ...)`, read with `return_base64=True`, then write with
  `content=&lt;base64&gt;` and `is_base64=True` so the tool decodes before
  writing. Writing a base64 string without `is_base64=True` stores the literal
  text and corrupts the file.
</Note>

<Note>
  `gx.progress.*` emits structured runtime events instead of relying on stdout.
  Successful and failed `execute_python_code` responses can return those events
  under `progress_events`, which makes multi-step Python workflows easier to
  inspect.
</Note>

<Tip>
  Use the SDK when Python needs multiple Genesis calls, local transforms
  between calls, larger intermediate artifacts, or structured progress
  updates. For one direct action, call the normal agent tool instead. For
  multi-step Genesis-aware Python workflows, activate and read the
  `genesis-sdk-python` skill first.
</Tip>

## Workspace files (local execution)

To read and write files under the bot's git repo or scratch area, import the
workspace roots from the `genesis` module (not `os.environ`):

```python theme={null}
from genesis import BOT_GIT_PATH, BOT_REPOS_PATH, BOT_SCRATCH_PATH, sanitize_path

path = f"{BOT_REPOS_PATH}/default/report.csv"   # repo working tree
with open(path, "w") as f:
    f.write(csv_text)
result = {"path": sanitize_path(path)}          # -> "BOT_REPOS_PATH/default/report.csv"
```

| Symbol | Purpose |
| - | - |
| `BOT_REPOS_PATH` | Git repos root (`repos/<repo_id>/...`) |
| `BOT_GIT_PATH` | Bot git workspace root |
| `BOT_SCRATCH_PATH` | Writable scratch directory for temporaries |
| `scan_id` | Active custom-scan session id in a scanner launcher; `None` outside a scan launcher |

The filesystem sandbox confines all reads and writes to these three roots and
refuses anything outside them. Use native `open()` for **repo working-tree**
files; use `gx.artifacts` for **artifact-store** outputs.

`sanitize_path(p)` rewrites an absolute workspace path to its `BOT_*_PATH`
shorthand so results stay host-agnostic. It also rewrites absolute paths from
the interpreter installation in tracebacks and diagnostics to `PYTHON_ROOT`;
the active managed-environment name remains visible when applicable. When
reporting where a file went, prefer repo-relative form (`repo_id` plus path) or
`sanitize_path(p)` instead of absolute host paths. If you return absolute
workspace paths without sanitizing, the executor rewrites them for you and sets
`paths_sanitized: true` on the response with a short notice.

## **Input Parameters for Each Function**

### **`python_exec`**

**Parameters**

| **Name** | **Definition** | **Format** |
| - | - | :-: |
| **code** | Python code to execute. Can be single line or multi-line block. | String (required) |
| **variables** | Dictionary of variables to make available in the execution context. | Object |
| **timeout** | Maximum execution time in seconds for local execution. Values are clamped to 1-600 (default: 10). | Integer |
| **return\_var** | Name of variable to return from execution context (default: returns all variables). | String |
| **libraries** | Additional libraries to import (beyond pre-loaded defaults). | Array of Strings |
| **safe\_mode** | Enable additional security restrictions (default: True). | Boolean |
| **secrets** | Optional list of Genesis vault secret names (`secret_*`) to inject into the execution environment as `SECRET_<NAME>` variables. Only stored `secret_*` names are accepted. Collect them first with `get_web_content(action="ask_user_for_secret")`. | Array of Strings |

<Tip>
  Use **variables** parameter to pass data from the agent context into your code. This is more efficient than embedding large data directly in code strings.
</Tip>

<Warning>
  Never hardcode API keys, passwords, or tokens in your Python code or tool arguments. Collect credentials with `get_web_content(action="ask_user_for_secret")` and pass the returned vault names in `secrets` so they stay out of chat history and source snippets. Do not put raw credential values in `secrets`.
</Warning>

## **Use Cases**

1. **Ad-Hoc Data Analysis**
   Perform quick calculations, statistical analysis, or data exploration without creating permanent functions or scripts.

2. **Data Transformation**
   Execute custom transformation logic on datasets that does not fit into standard SQL or built-in functions.

3. **API Integration**
   Make HTTP requests, parse responses, and integrate with external APIs dynamically based on user requirements.

4. **Prototyping & Testing**
   Test algorithms, validate assumptions, or prototype solutions before implementing them as permanent features.

5. **Custom Business Logic**
   Implement organization-specific calculations, rules, or validations that vary by use case or customer.

## **Workflow/How It Works**

1. **Step 1: Simple Calculation**

   Execute basic Python for quick results:

   ```python theme={null}
   python_exec(
       code="result = 42 * 365; print(f'Days in 42 years: {result}')"
   )
   ```

2. **Step 2: Data Analysis with Pandas**

   Analyze data using pre-loaded libraries:

   ```python theme={null}
   python_exec(
       code="""
   import pandas as pd
   import numpy as np

   data = {
       'product': ['A', 'B', 'C', 'D', 'E'],
       'sales': [150, 200, 175, 300, 225],
       'cost': [100, 150, 125, 200, 175]
   }

   df = pd.DataFrame(data)
   df['profit'] = df['sales'] - df['cost']
   df['margin'] = (df['profit'] / df['sales'] * 100).round(2)

   summary = {
       'total_sales': df['sales'].sum(),
       'total_profit': df['profit'].sum(),
       'avg_margin': df['margin'].mean(),
       'top_product': df.loc[df['profit'].idxmax(), 'product']
   }

   print("Sales Analysis:")
   print(df)
   print(f"Summary: {summary}")
   """
   )
   ```

3. **Step 3: Pass Variables from Context**

   Use data from previous operations:

   ```python theme={null}
   python_exec(
       code="""
   import pandas as pd

   df = pd.DataFrame(customer_data)

   df['segment'] = pd.cut(
       df['total_spend'], 
       bins=[0, 1000, 5000, float('inf')],
       labels=['Bronze', 'Silver', 'Gold']
   )

   segment_summary = df.groupby('segment').agg({
       'customer_id': 'count',
       'total_spend': 'sum'
   }).round(2)

   print(segment_summary)
   result = segment_summary.to_dict()
   """,
       variables={'customer_data': customer_data},
       return_var='result'
   )
   ```

4. **Step 4: API Integration**

   Make external API calls and process responses:

   ```python theme={null}
   python_exec(
       code="""
   import os
   import requests

   api_key = os.environ['SECRET_OPENWEATHER_API_KEY']

   response = requests.get(
       'https://api.openweathermap.org/data/2.5/weather',
       params={
           'q': city_name,
           'appid': api_key,
           'units': 'metric'
       }
   )

   if response.status_code == 200:
       weather_data = response.json()
       result = {
           'temperature': weather_data['main']['temp'],
           'humidity': weather_data['main']['humidity'],
           'description': weather_data['weather'][0]['description']
       }
       print(f"Weather in {city_name}: {result['temperature']}°C")
   else:
       result = {'error': f"API call failed: {response.status_code}"}
   """,
       variables={'city_name': 'London'},
       secrets=['secret_openweather_api_key'],
       return_var='result'
   )
   ```

5. **Step 5: File Operations**

   Read and write files within execution:

   ```python theme={null}
   python_exec(
       code="""
   import json
   from genesis import BOT_REPOS_PATH, sanitize_path

   config_path = f"{BOT_REPOS_PATH}/default/config.json"
   with open(config_path, 'r') as f:
       config = json.load(f)

   config['last_run'] = '2024-01-15'
   config['status'] = 'completed'

   with open(config_path, 'w') as f:
       json.dump(config, f, indent=2)

   print(f"Config updated: {config}")
   result = {'config': config, 'path': sanitize_path(config_path)}
   """,
       return_var='result'
   )
   ```

6. **Step 6: Complex Data Processing**

   Implement multi-step algorithms:

   ```python theme={null}
   python_exec(
       code="""
   import pandas as pd
   import numpy as np

   df = pd.DataFrame(transaction_data)
   df['date'] = pd.to_datetime(df['date'])
   df = df.sort_values('date')

   df['rolling_avg_7d'] = df['amount'].rolling(window=7).mean()
   df['rolling_sum_30d'] = df['amount'].rolling(window=30).sum()

   mean = df['amount'].mean()
   std = df['amount'].std()
   df['z_score'] = (df['amount'] - mean) / std
   df['is_anomaly'] = abs(df['z_score']) > 3

   anomalies = df[df['is_anomaly']]
   summary = {
       'total_transactions': len(df),
       'anomaly_count': len(anomalies),
       'anomaly_dates': anomalies['date'].dt.strftime('%Y-%m-%d').tolist(),
       'avg_7d_trend': df['rolling_avg_7d'].iloc[-1]
   }

   print(f"Detected {len(anomalies)} anomalies")
   result = summary
   """,
       variables={'transaction_data': transactions},
       return_var='result',
       timeout=60
   )
   ```

## **Integration Relevance**

* **data\_connector\_tools** to fetch data from databases, then process with custom Python code.
* **file** tools to read/write files before or after code execution.
* **github\_connector\_tools** / **git\_and\_file\_tools** (`git_action`, for GitLab) to version control generated scripts.
* **image\_tools** to process images or generate visualizations from code execution results.
* **web\_access\_tools** to fetch data via HTTP within executed code.
* **project\_manager\_tools** to execute custom code as part of automated mission tasks.

## **Configuration Details**

* **Execution Environment**: Python 3.9+ with isolated namespace per execution.
* **Pre-loaded Libraries**: pandas, numpy, requests, json, datetime, os, sys, re, math, statistics.
* **Resource Limits**: Local execution time limit (default 10s, max 600s), address-space cap `1,073,741,824` bytes, max file size `52,428,800` bytes, max `128` open files, and max `8` processes.
* **File System Access**: Reads and writes are confined to `BOT_GIT_PATH`, `BOT_REPOS_PATH`, and `BOT_SCRATCH_PATH` (import via `from genesis import ...`). Local execution may read task-owned documents and data in the task's own repository or scratch area, but not source-code files or sensitive files such as other threads' uploads, credentials, secrets, or `.git` internals. Local runs start in `BOT_SCRATCH_PATH`, which is also the temp root. You may write into the repo working tree under `BOT_REPOS_PATH` as well as scratch. Genesis stages a managed `child_runner.py` in scratch for each local run. Absolute workspace paths in responses are rewritten to `BOT_*_PATH` shorthands, and interpreter-installation paths to `PYTHON_ROOT`, before they reach the agent.
* **Network Access**: HTTP/HTTPS requests allowed; other protocols restricted.
* **Security Mode**: Blocks process creation, native library / FFI loading, dangerous filesystem probes, and other common sandbox-escape patterns. This is defense in depth, not a kernel-enforced boundary.
* **Return Value**: Can return primitive types, dictionaries, lists, or serializable objects.

<Warning>
  Code execution happens in a sandboxed environment, but always validate and sanitize user-provided code to prevent malicious operations. Never execute untrusted code without review.
</Warning>

## **Limitations or Notes**

1. **Execution Timeout**: Local execution defaults to 10 seconds and can run for up to 600 seconds (10 minutes). Long-running operations may be terminated once the timeout is reached.
2. **Memory Limits**: Default address-space cap is `1,073,741,824` bytes (\~1 GB). Large dataset operations may exceed limits and fail.
3. **No Subprocess**: Cannot spawn subprocesses, fork, or execute shell commands from local execution.
4. **No Native / FFI Loads**: Native library loading and common FFI bridges such as `ctypes` and `cffi` are blocked in local execution.
5. **Managed Dependencies**: Do not install packages from inside the running code. For local execution, create or update a named environment first, then rerun with `env="<name>"`.
6. **Local Inline Entry Point**: Local execution must use inline `code`; `script_path` is rejected, and local code cannot load or execute code from files. Use Snowpark for file-backed code execution.
7. **Network Limitations**: Only HTTP/HTTPS allowed; no raw socket access or other protocols.
8. **File System Scope**: Reads and writes are confined to `BOT_GIT_PATH`, `BOT_REPOS_PATH`, and `BOT_SCRATCH_PATH` (from `from genesis import ...`); task-owned documents and data may be read, but source-code and sensitive files are disallowed, and the sandbox refuses paths outside those roots. Low-level file descriptor access is blocked, and path-based operations such as `os.rename`, `os.replace`, `os.link`, `os.symlink`, `os.readlink`, `os.access`, `os.chmod`, `os.truncate`, and `os.utime` are enforced against the same allowed-path rules. Call `sanitize_path(p)` when returning file locations so output stays host-agnostic.
9. **Serialization**: Return values must be JSON-serializable or primitive types.
10. **State Persistence**: Each execution is isolated; no state persists between calls.
11. **Large Responses**: When the serialized `execute_python_code` response exceeds the inline Python budget (default `98,304` bytes / 96 KB, configurable with `GENESIS_TOOL_OUTPUT_PYTHON_BUDGET`), Genesis returns a capped envelope with `tool_output_capped`, `preview`, `truncation_info`, `full_output_ref`, and `agent_guidance` instead of the full inline payload.

When local static analysis refuses code, the response identifies the rule and
source line and includes `next_steps` with remediation guidance. Rule ids include
`dynamic_code_execution`, `builtins_access`, `sandbox_introspection`,
`process_spawn`, `native_ffi`, `account_enum`, `escape_probe`, `fs_probe`,
`syntax_error`, and `workspace_source_unreadable`. For an `fs_probe` refusal,
spell the allowed root directly using `from genesis import BOT_SCRATCH_PATH`
or `genesis.BOT_SCRATCH_PATH`, or use `os.environ["BOT_SCRATCH_PATH"]`; wrappers
such as `Path(...)`, `str(...)`, `os.path.join`, `/ "subdir"`, `.joinpath(...)`,
and f-strings remain supported when the root is statically provable. A caller-
supplied path, rebound root, or untraceable variable remains refused even if it
happens to point inside an allowed workspace.

### **Supported Operations**

✅ **Basic Python operations** - Variables, functions, loops, conditionals\
✅ **Data manipulation** - pandas DataFrames, numpy arrays, list/dict operations\
✅ **File I/O** - Read/write text and binary files in workspace\
✅ **HTTP requests** - GET, POST, PUT, DELETE with requests library\
✅ **JSON/CSV processing** - Parse and generate structured data formats\
✅ **Date/time calculations** - datetime, timedelta operations\
✅ **Regular expressions** - Pattern matching and text processing\
✅ **Mathematical operations** - Statistics, linear algebra, calculations\
✅ **String manipulation** - Formatting, parsing, encoding\
✅ **Exception handling** - Try/except blocks and error recovery

### **Not Supported**

❌ Installing new packages with `pip` during execution. Use `create_env` / `update_env` outside the running code instead.\
❌ Subprocess execution, shell launches, or process forking (`subprocess`, `os.system`, `pty`, etc.)\
❌ Native library / FFI loading (`ctypes`, `cffi`, similar bridges)\
❌ Disk-backed local execution via `script_path` or by loading additional local Python files\
❌ System file access outside the allowed repo/workspace and runtime import paths\
❌ Database connections (use data\_connector\_tools instead)\
❌ Multi-threading or multiprocessing\
❌ Raw socket programming\
❌ Modifying Python environment or interpreter\
❌ Accessing arbitrary host environment variables (except values explicitly injected by Genesis, such as managed scratch paths or secrets passed through `secrets`)\
❌ Infinite loops (terminated by timeout)\
❌ Heavy machine learning model training (use dedicated tools)

### **Output**

* **Success**: Execution result with returned variable(s), stdout output, and execution time.
* **Variables**: Dictionary of all variables in execution context (unless specific return\_var specified).
* **Standard Output**: Captured print statements and logging output. For local execution, `stdout` and `stderr` are each capped at `200,000` characters; larger streams are truncated with `... [truncated]` before the normal inline response budget is applied.
* **Capped Oversized Output**: `truncation_info` includes `bucket`, `bytes_in`, `bytes_out`, `budget_bytes`, and `spill_path`. When `full_output_ref` is not `null`, the full output is saved under `truncated_tool_outputs/<thread_id>/...` in the `apps` BotGit repo and can be paged back with `file(action="read", file_path=full_output_ref, repo_id="apps", start_byte=0, max_bytes=N)`, continuing from each response's `continuation.next_start_byte`. The byte range is the read shape that returns the saved copy exactly as written; the whole-file and line-window paths read in text mode and rewrite line endings.
* The accompanying `agent_guidance` explains that oversized output is routinely
  stored this way, is not a context limit or an error, and can be read back from
  the spill path without data loss. If saving the spill copy fails, it instead
  says that no spill file is available and recommends rerunning with narrower
  parameters.
* **Truncation record**: Over-budget JSON objects are shrunk in place when possible:
  every key at every depth is preserved, and trailing elements are removed from the
  longest lists first. The returned object includes `tool_output_truncation` with
  `truncated`, `truncation_basis`, `truncated_keys`, `bytes_before`, `bytes_after`,
  `full_output_ref`, and `agent_guidance`. For each shortened list, `truncated_keys`
  reports its JSON key path as an array plus the `kept` and `total` element counts.
  This means a missing key was not silently dropped by the cap; only reported list
  elements may be absent. The governor measures candidate payloads against the configured
  byte budget and keeps as many list elements as fit; the result is not decided by a fixed
  count of restoration attempts. Use `bytes_after` and each entry's `kept`/`total` counts
  to see the actual delivered size and what was omitted.
* **Amended next step**: When a shrunk object carries a `next` call shape (a `verb` plus a
  string `why` — the directive the tool computed over the whole result), the shortening is
  stated at the front of `why`: which lists were shortened with their `kept`/`total`
  counts, and the way to the rest (the `full_output_ref` path with the
  `file(action="read", ...)` call that reads it, or advice to narrow the call when no spill
  copy was saved). `verb`, `args` and the tool's own sentence are preserved. A `next` that
  is not a call shape is left untouched.
* **Tail-cut fallback**: Non-object payloads and objects that cannot be shrunk under
  the budget keep the capped envelope (`tool_output_capped`, `preview`,
  `truncation_info`, `full_output_ref`, and `agent_guidance`) and also include the
  same `tool_output_truncation` record. Its `truncation_basis` identifies why the
  fallback was used (`not_an_object`, `object_irreducible`, `record_key_in_use`,
  `serialized_key_collision`, or `structure_unwalkable`), and a compact copy of the
  record's measurements is appended on a trailer line in `preview` when that trailer
  fits within the budget.
* **Execution Time**: Time taken to execute code in seconds.
* **Errors**: Exception type, error message, and full stack trace for debugging.
* **Local Failure Metadata**: Failed local runs can also include `status`, `error_type`, `policy_violations`, and `metrics`. `error_type` is the reported exception class name. `status` is one of `user_error`, `policy_denied`, `resource_limit`, or `internal_error`. `metrics` includes `wall_ms`, `cpu_ms`, `peak_rss_bytes`, `applied_limits`, and `skipped_limits`.
* **Safety-Judge Denials**: A request denied by the local safety judge includes a fixed, actionable `safety_guidance.reason` instead of the judge's free-form explanation. `judge_reason_code` identifies the category: `OUTSIDE_ROOTS`, `SOURCE_READ`, `CODE_EXEC_FROM_FILE`, `PROCESS_OR_ESCAPE`, `NATIVE_BYPASS`, `HOST_PROBE`, `NETWORK`, `SENSITIVE_FILE`, or `OTHER`. `NETWORK` indicates code tried to open a socket, HTTP, or database connection to a private, internal, or Outpost-routed host; use a Genesis connection to reach that system instead.
* **Safety-Judge Unavailable**: If the local safety judge fails or returns no decision, `safety_guidance` identifies this as an outage. For a request-side failure, the code does not run; for an output-side failure, the code has already run and its output is withheld, so do not retry it because its side effects may have happened. Operators can check the active provider's model assignments and the server log's sanitized `judge_error` diagnostic.
* **Path Sanitization**: When a response contains absolute workspace paths, the local executor rewrites them to `BOT_GIT_PATH` / `BOT_REPOS_PATH` / `BOT_SCRATCH_PATH` shorthands and may set `paths_sanitized: true` with a `notice` suggesting `sanitize_path(p)` for future runs.
* **AWS/EKS Sandbox Guidance**: When the request or response mentions `boto3`, AWS SDK work, EKS/Kubernetes, Helm, `kubectl`, AWS CLI, cloud deployment, or cloud monitoring, Genesis can add `agent_reminders`, `sandbox_tools_recommended`, and `sandbox_tools_reference` to recommend `sandbox_action` plus the `aws-eks-sandbox-operations` skill.
* **Warnings**: Any resource warnings (approaching timeout, high memory usage).

## **Best Practices**

<CardGroup cols={2}>
  <Card title="Small & Focused" icon="bullseye">
    Keep code blocks focused on single tasks. Break complex operations into multiple executions.
  </Card>

  <Card title="Error Handling" icon="shield-check">
    Always use try/except blocks for operations that might fail (API calls, file I/O, parsing).
  </Card>

  <Card title="Resource Awareness" icon="gauge">
    Monitor execution time and memory usage. Use sampling for large datasets.
  </Card>

  <Card title="Data Validation" icon="check-double">
    Validate input data and function parameters before processing to avoid runtime errors.
  </Card>

  <Card title="Logging" icon="file-lines">
    Use print statements to track execution progress and debug issues.
  </Card>

  <Card title="Return Values" icon="arrow-turn-up">
    Always assign results to variables for retrieval. Do not rely solely on print output.
  </Card>
</CardGroup>

## **Example: Complete Data Analysis Workflow**

```python theme={null}
# Step 1: Fetch data from database
query_result = _query_database(
    connection_id="analytics_db",
    query="SELECT customer_id, order_date, order_amount, product_category FROM orders WHERE order_date >= '2024-01-01' LIMIT 10000",
    max_rows=10000
)

# Step 2: Perform complex analysis
analysis_result = python_exec(
    code="""
import pandas as pd
import numpy as np

df = pd.DataFrame(data)
df['order_date'] = pd.to_datetime(df['order_date'])
df['order_amount'] = pd.to_numeric(df['order_amount'], errors='coerce')
df = df.dropna()

print(f"Loaded {len(df)} orders")

customer_stats = df.groupby('customer_id').agg({
    'order_amount': ['sum', 'mean', 'count'],
    'order_date': ['min', 'max']
}).reset_index()

customer_stats.columns = ['customer_id', 'total_spend', 'avg_order', 'order_count', 'first_order', 'last_order']
customer_stats['lifetime_days'] = (customer_stats['last_order'] - customer_stats['first_order']).dt.days

def segment_customer(row):
    if row['total_spend'] > 5000:
        return 'VIP'
    elif row['total_spend'] > 2000:
        return 'Gold'
    elif row['total_spend'] > 500:
        return 'Silver'
    else:
        return 'Bronze'

customer_stats['segment'] = customer_stats.apply(segment_customer, axis=1)

category_stats = df.groupby('product_category').agg({
    'order_amount': ['sum', 'mean', 'count'],
    'customer_id': 'nunique'
}).reset_index()

category_stats.columns = ['category', 'total_revenue', 'avg_order', 'order_count', 'unique_customers']
category_stats = category_stats.sort_values('total_revenue', ascending=False)

daily_sales = df.groupby(df['order_date'].dt.date)['order_amount'].agg(['sum', 'count']).reset_index()
daily_sales.columns = ['date', 'revenue', 'orders']
daily_sales['avg_order_value'] = (daily_sales['revenue'] / daily_sales['orders']).round(2)
daily_sales['revenue_7d_avg'] = daily_sales['revenue'].rolling(window=7).mean().round(2)
daily_sales['revenue_growth'] = daily_sales['revenue'].pct_change() * 100

summary = {
    'total_revenue': float(df['order_amount'].sum()),
    'total_orders': len(df),
    'unique_customers': df['customer_id'].nunique(),
    'avg_order_value': float(df['order_amount'].mean()),
    'segments': customer_stats['segment'].value_counts().to_dict(),
    'top_category': category_stats.iloc[0]['category'],
    'top_category_revenue': float(category_stats.iloc[0]['total_revenue'])
}

result = {
    'summary': summary,
    'customer_segments': customer_stats.to_dict('records'),
    'category_performance': category_stats.to_dict('records'),
    'daily_trends': daily_sales.tail(30).to_dict('records')
}
""",
    variables={'data': query_result['data']},
    return_var='result',
    timeout=60
)

print(f"Summary: {analysis_result['result']['summary']}")
```

## **Advanced Features**

### **Statistical Analysis**

```python theme={null}
python_exec(
    code="""
import numpy as np
from scipy import stats

data = np.array(values)

result = {
    'mean': float(np.mean(data)),
    'median': float(np.median(data)),
    'std': float(np.std(data)),
    'min': float(np.min(data)),
    'max': float(np.max(data)),
    'q25': float(np.percentile(data, 25)),
    'q75': float(np.percentile(data, 75))
}

stat, p_value = stats.normaltest(data)
result['is_normal'] = p_value > 0.05
result['normality_p_value'] = float(p_value)

print(f"Distribution analysis: {result}")
""",
    variables={'values': [23, 45, 67, 89, 34, 56, 78, 90, 12, 45]},
    return_var='result'
)
```

### **Text Processing**

```python theme={null}
python_exec(
    code="""
import re
from collections import Counter

text = text_data.lower()
text = re.sub(r'[^a-z0-9 ]', '', text)
words = text.split()

stop_words = {'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for'}
words = [w for w in words if w not in stop_words and len(w) > 2]

word_freq = Counter(words)
top_words = word_freq.most_common(20)

result = {
    'total_words': len(words),
    'unique_words': len(set(words)),
    'top_words': [{'word': w, 'count': c} for w, c in top_words]
}

print(f"Analyzed {result['total_words']} words")
""",
    variables={'text_data': long_text_content},
    return_var='result'
)
```

### **Data Validation**

```python theme={null}
python_exec(
    code="""
import pandas as pd

df = pd.DataFrame(dataset)

validation_results = {
    'row_count': len(df),
    'column_count': len(df.columns),
    'missing_values': df.isnull().sum().to_dict(),
    'duplicate_rows': df.duplicated().sum(),
    'data_types': df.dtypes.astype(str).to_dict()
}

errors = []

required_cols = ['customer_id', 'order_date', 'amount']
missing_cols = [col for col in required_cols if col not in df.columns]
if missing_cols:
    errors.append(f"Missing required columns: {missing_cols}")

if 'amount' in df.columns:
    negative_amounts = (df['amount'] < 0).sum()
    if negative_amounts > 0:
        errors.append(f"Found {negative_amounts} negative amounts")

if 'order_date' in df.columns:
    try:
        pd.to_datetime(df['order_date'])
    except:
        errors.append("Invalid date format in order_date column")

validation_results['errors'] = errors
validation_results['is_valid'] = len(errors) == 0

print(f"Validation {'passed' if validation_results['is_valid'] else 'failed'}")
result = validation_results
""",
    variables={'dataset': data_to_validate},
    return_var='result'
)
```

### **API Pagination Handler**

```python theme={null}
python_exec(
    code="""
import os
import requests
import time

def fetch_paginated_data(base_url, api_key, max_pages=10):
    all_data = []
    page = 1
    
    while page <= max_pages:
        response = requests.get(
            base_url,
            params={'page': page, 'per_page': 100},
            headers={'Authorization': f'Bearer {api_key}'}
        )
        
        if response.status_code != 200:
            print(f"Error on page {page}: {response.status_code}")
            break
        
        data = response.json()
        if not data.get('items'):
            break
        
        all_data.extend(data['items'])
        print(f"Fetched page {page}: {len(data['items'])} items")
        
        if not data.get('has_next'):
            break
        
        page += 1
        time.sleep(0.5)
    
    return all_data

result = fetch_paginated_data(api_url, os.environ['SECRET_EXAMPLE_API_TOKEN'])
print(f"Total items fetched: {len(result)}")
""",
    variables={'api_url': 'https://api.example.com/data'},
    secrets=['secret_example_api_token'],
    return_var='result',
    timeout=120
)
```

## **Troubleshooting**

<AccordionGroup>
  <Accordion title="Execution Timeout">
    * Reduce dataset size or use sampling
    * Optimize algorithms (vectorize operations with numpy/pandas)
    * Increase timeout parameter (up to 600 seconds for local execution)
    * Break into smaller execution steps
    * Use generators or lazy evaluation for large data
  </Accordion>

  <Accordion title="Memory Error">
    * Process data in chunks instead of loading all at once
    * Use pandas iterator options (chunksize parameter)
    * Delete large intermediate variables with del variable
    * Use more memory-efficient data types (int8 vs int64)
    * Consider using data\_connector\_tools for heavy processing
  </Accordion>

  <Accordion title="Import Error - Module Not Found">
    * If you are using local execution, create a named environment with `create_env(name=..., deps=[...])`.
    * If the environment already exists, inspect it with `list_env_deps(venv=...)` and add missing packages with `update_env(name=..., add_packages=[...])`.
    * Reuse that same environment name with `execute_python_code(..., env=...)`.
    * If managed package installation is unavailable in the current runtime, continue with a stdlib-only approach or switch to Snowpark with approval.
    * **Exception — `genesis_sdk`:** the Genesis SDK is provided by the Genesis runtime image itself (`/app/genesis_sdk`), not by PyPI. Do **not** call `create_env(deps=['genesis-sdk'])`, `create_env(deps=['genesis_sdk'])`, `update_env(add_packages=['genesis-sdk'])`, or `update_env(add_packages=['genesis_sdk'])` — the public PyPI packages of those names are unrelated and will not satisfy `from genesis_sdk import Genesis`. If the import fails on a deployed Genesis runtime, that is a deployment/packaging regression — report it (file a CLI ticket) rather than attempting to install a workaround.
  </Accordion>

  <Accordion title="File Not Found">
    * Build paths from `from genesis import BOT_GIT_PATH, BOT_REPOS_PATH, BOT_SCRATCH_PATH`
    * Use `f"{BOT_REPOS_PATH}/<repo_id>/..."` for repo working-tree files
    * Check file exists using `os.path.exists()` on a path rooted at one of the workspace globals
    * Ensure file was created in a previous step under the same root
    * Writes outside `BOT_GIT_PATH`, `BOT_REPOS_PATH`, or `BOT_SCRATCH_PATH` are refused by the sandbox
  </Accordion>

  <Accordion title="Serialization Error on Return">
    * Convert numpy arrays to lists: array.tolist()
    * Convert pandas DataFrames to dicts: df.to\_dict()
    * Use float() for numpy float types
    * Use int() for numpy integer types
    * Convert datetime to ISO strings: dt.isoformat()
  </Accordion>

  <Accordion title="API Request Failed">
    * Check internet connectivity (if applicable)
    * Verify API endpoint URL is correct
    * Check authentication credentials
    * Add error handling with try/except
    * Check for rate limiting and add delays
    * Verify API response format matches expectations
  </Accordion>

  <Accordion title="Syntax Error in Code">
    * Check for proper indentation (use 4 spaces)
    * Verify quotes are properly closed
    * Check for balanced parentheses/brackets
    * Test code in local Python environment first
    * Use syntax highlighter to identify issues
  </Accordion>

  <Accordion title="Snowpark Connection or Stage Errors">
    * `STAGE_REQUIRES_SNOWFLAKE_CONNECTION`: the deployment metadata store is not Snowflake — pass a saved Snowflake `connection_id` or use `executor="local"`
    * `CONNECTION_DATABASE_UNAVAILABLE`: the connection's configured database is missing or the role lacks `USAGE` — set `database` and `schema` on the connection and grant access, or choose a different `connection_id`
    * `type: connection_disabled`: the System `Snowflake` connection is hidden — use a user-created Snowflake connection id instead of the default
  </Accordion>
</AccordionGroup>

## **Security Considerations**

<Warning>
  **Code Execution Risks**: Always validate user-provided code before execution. Never execute code from untrusted sources without thorough review.
</Warning>

### **Sandbox Protections**

The code executor implements multiple security layers:

* **Restricted Imports**: Blocks process-launch and native/FFI escape paths in local execution, including common modules used for host probing
* **File System Isolation**: Reads and writes are confined to `BOT_GIT_PATH`, `BOT_REPOS_PATH`, and `BOT_SCRATCH_PATH`; task-owned documents and data may be read, but source-code and sensitive-file reads are blocked even under those roots. Host paths outside those roots are refused. Responses sanitize absolute workspace paths to `BOT_*_PATH` shorthands
* **Process Blocking**: Local execution blocks subprocesses, forks, shell launches, and related process-creation APIs
* **Native Library Blocking**: Local execution blocks `ctypes`, `cffi`, and similar native loading paths
* **Network Filtering**: Only HTTP/HTTPS; no raw sockets or other protocols
* **Resource Limits**: CPU time and memory caps prevent denial-of-service
* **Namespace Isolation**: Each execution has isolated variable scope
* **No Privilege Escalation**: Sensitive shell/user environment variables are scrubbed before privilege-drop execution, and the local hardening is defense in depth rather than full kernel-enforced isolation

In the full Genesis Databricks App, `execute_python_code` and package installs
use the confinement configured for that deployment; see [Deploying Genesis on Databricks](/docs/deployments/Databricks/Genesis-On-Databricks#genesis-as-a-databricks-app).

### **Safe Coding Practices**

<CardGroup cols={2}>
  <Card title="Input Validation" icon="filter">
    Validate and sanitize all user inputs before using them in code execution.
  </Card>

  <Card title="Error Containment" icon="shield">
    Use try/except blocks to prevent error propagation and information leakage.
  </Card>

  <Card title="Resource Monitoring" icon="gauge-high">
    Monitor execution time and memory usage. Set appropriate timeouts.
  </Card>

  <Card title="Audit Logging" icon="file-contract">
    Genesis records code executions and local safety-guard decisions with
    runtime context, including `bot_id`, `thread_id`, and `user_id`, for
    security auditing.
  </Card>
</CardGroup>

## **Performance Optimization**

### **Efficient Data Processing**

```python theme={null}
# Inefficient - Row-by-row iteration
python_exec(
    code="""
result = []
for row in data:
    result.append(row['value'] * 2)
"""
)

# Efficient - Vectorized operations
python_exec(
    code="""
import pandas as pd
df = pd.DataFrame(data)
result = (df['value'] * 2).tolist()
"""
)
```

### **Memory Management**

```python theme={null}
python_exec(
    code="""
import pandas as pd

chunks = []
for chunk in pd.read_csv('large_file.csv', chunksize=10000):
    processed = chunk[chunk['amount'] > 100]
    chunks.append(processed)

result = pd.concat(chunks, ignore_index=True)
del chunks
"""
)
```
