ADR-components-002
Remove BaseEnv — environments are NodeSets
Context
BaseEnv and BaseNodeSet had nearly identical interfaces (get_tools(), initialize(), shutdown()). BaseEnv added only create_manager() which returned a BaseEnvManager singleton. The env_mgr parameter was threaded through the entire execution pipeline (LoopRunner.run() → GraphExecutor.run() → _fire_node() → handler.execute(inputs, ctx, env_mgr)) just for 7 out of 18+ node handlers. The other 11+ nodes received and ignored it. This created an unnecessary abstraction layer and made the executor domain-aware.
Decision
(1) Delete BaseEnv class and BaseEnvManager ABC. (2) Environments become BaseNodeSet subclasses (e.g. EnvHabitatNodeSet) that expose an env_mgr property via duck typing. (3) Remove env_mgr from the execute signature: execute(inputs, ctx, env_mgr) → execute(inputs, ctx). (4) Remove built-in env nodes (envObserve, envStep, envState, envInfo) — replaced by nodeset tools wired on the canvas. (5) Nodes that still need simulator access (IterInNode, VLMCallNode, PolicyForwardNode) fetch it internally via registry.get_env_mgr(). (6) WorkspaceComponentRegistry.get_env_mgr() finds the first loaded nodeset with an env_mgr attribute. (7) Delete workspace/envs/ directory and app/env/ directory.
Alternatives
(a) Keep BaseEnv as separate concept — rejected, redundant with BaseNodeSet. (b) Create EnvNodeSet ABC inheriting BaseNodeSet — rejected, unnecessary abstraction layer; duck typing (getattr(ts, "env_mgr", None)) is simpler and achieves the same result.
Rationale
One fewer concept to learn. The executor becomes fully domain-agnostic — it fires nodes and passes data through wires with zero knowledge of environments. Environment tools appear in the sidebar catalog alongside all other tools. A single EnvHabitatNodeSet file works both locally (?mode=local) and as an auto-hosted server (?mode=server), leveraging ADR-server-001.
Affected docs
architecture.md, blueprint.md, glossary.md, roadmap.md, nodesets.md, capabilities/customizable-node-system.md