Runtime Safety
Understand Python process isolation, resource limits, failure behavior, and the trust boundary.
Each Python V2 session runs in a child process rather than inside the Rust process. If a hook loops forever, exhausts its allowed memory, or spawns too many children, Market Lab terminates the Python process group and fails the run without taking down mlabd.
Default limits
These limits apply when the server sandbox is not enabled.
| Resource | Limit |
|---|---|
| Manifest inspection and process startup | 30 seconds |
Each on_data call | 5 seconds |
Each on_execution call | 5 seconds |
on_finish | 60 seconds |
| Aggregate Python process-tree memory | 2 GiB |
| Python process tree | 32 processes |
| One internal protocol message | 8 MiB |
| Cumulative Python stdout and stderr | 64 MiB |
The memory and process count cover the entire Python process group, including child processes created by packages. Monitoring continues between hooks, not only while a hook is returning.
When a hook-time, memory, process-count, or protocol limit is exceeded, Market Lab:
- stops accepting output from the hook;
- kills the Python process group;
- clears execution commands that were not completed by the failed hook; and
- records the failure in the script job and runtime report.
The log limit behaves differently: after 64 MiB, further Python output is discarded rather than terminating the run. These limits are fixed runtime safeguards in v0.0.8. They are not script parameters.
Infinite loops
This hook is terminated after five seconds:
def on_data(ctx, history):
while True:
passThe job fails with a timeout error. Later events are not delivered to a replacement Python process inside that same run.
Memory exhaustion
Memory is measured across the process tree. A script cannot bypass the limit by moving an allocation into a child process:
def on_data(ctx, history):
data = bytearray(3 * 1024 * 1024 * 1024)On Linux, Market Lab reads resident memory for processes in the Python process group through /proc. On macOS, it uses the operating system's physical-footprint accounting. Process-group termination and hook timeouts are supported on both platforms.
Logs and print
print(...), tracebacks, and normal Python stderr are forwarded into the Market Lab job logs:
mlab script logs <JOB_ID> --followThe Python bridge uses a separate internal channel, so normal printing does not corrupt runtime messages. After 64 MiB of cumulative Python log output, further output is discarded and Market Lab writes one truncation notice.
Failure behavior
An uncaught Python exception fails the current hook and includes its traceback in the Market Lab error. Because hooks are serialized, the runtime does not continue to the next event after a fatal hook failure.
on_finish runs when a backtest finishes or a live session ends through duration expiry, a stop request, SIGTERM, or an interrupt. It is not guaranteed after a process crash, a resource-limit kill, or an abrupt machine shutdown. Do not rely on it as the only place to persist critical state.
Live order signing, credentials, nonces, account streams, and execution journals remain inside mlabd. Delegated private keys are not serialized into the Python context or internal hook messages.
Trust boundary
By default, process isolation is a reliability boundary, not a security sandbox.
A Python script can use the current daemon user's permissions to:
- read and write accessible files;
- open network connections;
- inspect inherited environment variables;
- start subprocesses within the process-count limit; and
- import native extensions installed in its environment.
Run only code and dependencies you trust. With the Native backend, these permissions are those of the operating-system user running mlabd. With Docker, they are constrained by the daemon container, which still has intentional access to Market Lab state, credentials, and outbound networking. See Market Lab Daemon for the complete boundary.
Do not put secrets directly in a script, its parameters, logs, returned metadata, or artifacts.
Python sandbox
The Python sandbox is for developers building a hosted platform on the Market Lab CLI, where users submit their own scripts. It runs that code in a restricted environment, separate from the daemon's credentials and unrelated files.
You do not need to enable it for normal use of the CLI installed on your computer. Leave MLAB_PYTHON_SANDBOX unset and use your own Python environment and packages. Only run scripts you trust outside the sandbox.
Enable on a server
Set MLAB_PYTHON_SANDBOX=required in the trusted launcher and daemon environment, not as a user-controlled script setting.
Use matching mlab and mlabd builds from v0.1.77 or later on Linux 6.12+ with Landlock ABI 6 and seccomp enabled. Mount /tmp as tmpfs with a maximum size of 256 MiB.
Run inside the assigned Linux runtime, using the daemon's MLAB_HOME:
MLAB_PYTHON_SANDBOX=required mlab script precheck strategy.py \
--from "2026-09-30 12:00:00" \
--to "2026-09-30 12:10:00" \
--output jsonThe command validates the script and runs the backtest simulator. It places no real orders. Choose a window of at most 24 hours and 1,000 source events.
- Python cannot access the network, unrelated files, secrets in the parent environment, or launch child processes and threads.
- Each worker uses the image's Python and has a 512 MiB address-space limit. Custom interpreters, virtual environments, and Jupyter are not supported under this policy.
- A pass is saved in
MLAB_HOME/prechecks. Changing the script, exact--paramarguments, or CLI version requires another precheck before deployment.
The sandbox remains active during live execution; passing precheck does not prove every code path is correct. Unsupported systems refuse to run. Selecting the Docker daemon on macOS does not forward this command: run it inside Linux.
Available packages
The daemon image includes these data-analysis packages for sandboxed scripts. Import them directly; no per-user installation is needed.
| Package | Import | Use |
|---|---|---|
| NumPy | import numpy as np | Arrays and numerical calculations |
| pandas | import pandas as pd | Tables, rolling windows and time series |
| SciPy | import scipy | Statistics, optimization and signal processing |
| statsmodels | import statsmodels.api as sm | Regression and time-series models |
| scikit-learn | import sklearn | Preprocessing and machine learning |
| Matplotlib | import matplotlib.pyplot as plt | Save charts as images |
| Seaborn | import seaborn as sns | Statistical charts |
| Plotly | import plotly.graph_objects as go | Interactive HTML charts |
Versions are pinned in the CLI repository's python/requirements.txt. Update the daemon image to receive package updates. This bundled environment does not replace the Python environment used by your local CLI.
- Runtime package installation and network access remain blocked.
- Use one worker, such as
n_jobs=1. Additional processes and threads are blocked. - Save output through
ctx.artifact_path(). Matplotlib usesAgg; save figures rather than callingplt.show(). - Export Plotly with
include_plotlyjs=True, auto_open=False. HTML artifacts are downloads; browser-based image export through Kaleido is not included. - Memory, execution-time and artifact limits still apply.
See artifacts for chart and table examples.
Inspect runtime limits
Backtest and job reports identify the python engine and record hook counts, failures, durations, and the active Python limits. Use script status and structured output when diagnosing a slow or failed strategy:
mlab script status <JOB_ID> --output json
mlab script logs <JOB_ID> --output jsonl