MarketlabMarketlabDocs
Scripting V2 - PythonPlain Python Files

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.

ResourceLimit
Manifest inspection and process startup30 seconds
Each on_data call5 seconds
Each on_execution call5 seconds
on_finish60 seconds
Aggregate Python process-tree memory2 GiB
Python process tree32 processes
One internal protocol message8 MiB
Cumulative Python stdout and stderr64 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:

  1. stops accepting output from the hook;
  2. kills the Python process group;
  3. clears execution commands that were not completed by the failed hook; and
  4. 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:
        pass

The 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> --follow

The 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 json

The 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 --param arguments, 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.

PackageImportUse
NumPyimport numpy as npArrays and numerical calculations
pandasimport pandas as pdTables, rolling windows and time series
SciPyimport scipyStatistics, optimization and signal processing
statsmodelsimport statsmodels.api as smRegression and time-series models
scikit-learnimport sklearnPreprocessing and machine learning
Matplotlibimport matplotlib.pyplot as pltSave charts as images
Seabornimport seaborn as snsStatistical charts
Plotlyimport plotly.graph_objects as goInteractive 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 uses Agg; save figures rather than calling plt.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

On this page