Record the Provider Contract
Use the provider’s official SDK and API documentation as the source of truth. Record authentication and account scope; mutually exclusive image, snapshot, or template selectors; workspace persistence; CPU, memory, disk, GPU, placement, and quotas; startup and deletion semantics; enforceable network modes; command, transfer, endpoint, cancellation, and error behavior; and async or thread-safety guarantees.Create the Minimal File
Start with one provider module and one package export:example_local.py as follows:
EnvironmentSession method and both abstract BaseEnvironment methods. There is no separate public EnvironmentPlan type: providers consume the Recipe-adjusted ExecutionPlan, and build_config(req, plan) reads plan.environment.params while validating the resolved network phases.
The wrapper is only a contract exercise. A production provider should call its own SDK and return its own EnvironmentSession; it should not depend on HostProcessSession.
Export and Inspect the Registration
Add the import tosrc/agentcompass/environments/__init__.py:
example_local. The second should list workspace and default_workspace_root with their defaults and descriptions. If importing an optional provider SDK can fail, guard only its documented missing dependency in __init__.py; do not swallow unrelated exceptions or registration errors.
Run One Task
Use the companion Benchmark and Harness tutorial components to exercise provider open, session construction, and close without external credentials:paths.run_info; its parent directory is the run directory. In run_info.json, confirm that request → environment → id is example_local and that resolved_execution_plans contains the same Environment ID for attempt 1. Also confirm that one details/*.json file and summary.md exist. The .agentcompass/environment-smoke directory confirms open() used the provider config; it is not a result directory.
For a remote provider, add one session-level check that runs a list-form command, writes and reads UTF-8 text, uploads and downloads one file and one directory, and verifies cleanup in the provider console. A successful registry or local mock check does not prove remote lifecycle or network enforcement.
Map the Real Session Primitives
Implement the methods with these semantics:
Normalize provider responses into
ExecResult. A command’s nonzero return code is data, not a provider exception; raise only when transport or provider execution itself fails. Preserve timeout versus provider-error meaning. Use async SDK methods when available, and explicitly isolate blocking calls so high task concurrency does not block the event loop.
Own Open, Close, and Partial Cleanup
Duringopen(), build and validate provider config from the resolved plan; resolve mutually exclusive selectors; apply resources, workspace, labels, and baseline network policy; create the sandbox within the startup timeout; and construct a session only after the provider reports a usable state. If any step fails, release every partially created resource before propagating the error.
During close(), stop or delete the exact resource owned by that session. Make cleanup safe after partial startup and sufficiently idempotent for cancellation or repeated error handling. Never discover cleanup targets through broad names or unvalidated global searches.
Declare supported_network_modes, supported_allowlist_entry_types, supports_network_target_ports, and supports_dynamic_network_policy from real enforcement capability. Fail closed when a mode, target type, or port restriction cannot be enforced. Do not advertise restrictions implemented only by prompts, environment variables, or best-effort agent instructions.
Dynamic providers must switch from baseline to run policy and, for reused evaluation, directly from run to evaluation policy. Protect and redact proxy credentials, policy tokens, signed URLs, and generated endpoints, and remove temporary networks or policies after normal close and startup failure.
Preserve Config and Recipe Precedence
Define one typed config field for every public provider setting. Keep authentication, sandbox source, lifecycle timeouts, resources, workspace, and provider metadata distinct; use clear units, defaults, validation, and mutual-exclusion errors. Credentials must not enter logs or persisted plans. Environment code consumes the final plan while Recipes supply Benchmark-specific defaults. Both layers preserve:BaseEnvironment, plus the provider’s SDK request limits, account quotas, and capacity. Log stable sandbox IDs, lifecycle phases, elapsed time, selected non-secret images, and actionable errors; never log full config dictionaries that may contain secrets.
Diagnose Failures by Stage
The simplest real reference is
host_process.py. For image lifecycle, command execution, transfer, and enforceable network behavior in a container provider, compare docker.py.