tools/environments/. Third-party
sandbox vendors integrate as plugins instead — a standalone plugin repo
installed under ~/.mibyan/plugins/, registering a backend the user selects
exactly like a built-in one via terminal.backend in config.yaml.
This page mirrors the Browser Provider Plugins
guide — same registration flow, same scope semantics.
What a provider controls
A registered backend automatically participates in every core surface:
Declaring these flags on the provider closes the classic “new backend missed
classification site N” bug class — the core consults the registry at each
site instead of a hardcoded list of names.
Minimal provider
~/.mibyan/plugins/acmebox/__init__.py
~/.mibyan/plugins/acmebox/plugin.yaml
Rules
- Reserved names. Registrations that collide with a built-in backend name
(
local,docker,singularity,modal,managed_modal,daytona,vercel_sandbox,ssh) are rejected. Plugins extend the backend set; they never shadow in-tree backends. create_environmentmust accept**kwargsand ignore unknown keys — the forward-compat contract that lets the factory signature evolve without breaking older plugins.is_available()/probe()must be cheap. No network calls — they run during requirement checks and UI paints.- Fail-soft everywhere. A provider attribute that raises is treated as
its default by the core (e.g. a raising
skip_container_guardskeeps the approval layer ON). Don’t rely on exceptions for control flow. - Secrets belong in
strip_env_keys. Your vendor token must never be readable by a model-authored shell command; listing it strips it from every spawned subprocess unconditionally, like the built-inMODAL_*/DAYTONA_API_KEYhandling.
Environment object contract
create_environment() returns an object satisfying the same duck-typed
interface as tools.environments.base.BaseEnvironment:
execute(command, timeout=None, ...)→{"output": str, "exit_code": int}cleanup()— release resources; called on session teardown / idle reaping- Optional: persistence hooks mirroring the built-in cloud backends
BaseEnvironment is recommended (you inherit the shared file-sync
and background-process plumbing) but not required.
Session isolation semantics
If your sandbox is resumed by name (a durable VM the backend re-attaches to), setsession_isolated_when_nonpersistent = True. With
terminal.container_persistent: false, each session then gets its own
sandbox identity instead of sharing one — without this, two independent
ephemeral runs could attach one live VM and delete it out from under each
other.
