- ADR-036: Resource DAG Operational Semantics (10 purposes, sandbox boundary algebra) - ADR-037: Tool Reachability and Access Projection (transitive reach, read/write routing) - ADR-038: Cross-Mechanism Sandbox Coordination (coherence, write-then-sync, lazy materialization) - ADR-039: Container and Execution Environment Resource Types (9 engine-agnostic types) - ADR-040: Language Server Protocol Resource Types (lsp-server, lsp-workspace, lsp-document) - Updated specification.md with 7 new subsections for operational semantics - Updated resource_dag.md reference doc with operational semantics section - Updated ADR-008, ADR-011, ADR-015, ADR-027 with cross-references - Resolved merge conflicts from cherry-pick renumbering (033-037 -> 036-040) - Fixed all stale display-text references across all files
18 KiB
ADR-039: Container and Execution Environment Resource Types
Status: Accepted
Date: 2026-02-21
Supersedes: None
Author(s): Jeffrey Phillips Freeman Jeffrey.Freeman@CleverThis.com
Approver(s): Jeffrey Phillips Freeman Jeffrey.Freeman@CleverThis.com
Context
CleverAgents operates on diverse resources — git repositories, filesystems, databases, APIs — but the current 24 built-in resource types do not model containerized environments. Modern development workflows depend heavily on containers for reproducible builds, isolated tool execution, and consistent development environments. Tools, LSP servers, and other executables may be available only inside specific containers. The system needs resource types that represent container engines, images, instances, mounts, volumes, and execution environments so that the resource DAG can reason about tool availability, sandbox coordination across host and container boundaries, and equivalence between host files and container-mounted files.
These types must be engine-agnostic — representing containers abstractly regardless of whether the underlying engine is Docker, Podman, containerd, LXC/LXD, CRI-O, or another runtime.
Decision
CleverAgents adds seven new built-in physical resource types for modeling containerized environments, plus one type for executable discovery. These types integrate into the existing resource DAG with containment edges, virtual equivalence links (for files accessible through both host and container), and reference edges (for tool/executable dependencies).
Design
New Resource Types
Container Layer (7 types)
container-runtime
The container engine installation — a running daemon or CLI tool that manages containers.
| Field | Value |
|---|---|
| Kind | physical |
| Sandbox strategy | none |
| User-addable | yes |
| CLI arguments | --engine-type (required: docker, podman, containerd, lxc, lxd, cri-o, other), --socket-path (optional), --endpoint (optional), --version (optional) |
| Allowed parents | (none — top-level resource) |
| Allowed children | container-image (0..*), container-instance (0..*), container-volume (0..*), container-network (0..*) |
| Auto-discovery | Discovers running instances, pulled images, created volumes, and configured networks from the engine |
| Capabilities | read: true, write: false, sandbox: false, checkpoint: false |
Properties: engine_type (docker | podman | containerd | lxc | lxd | cri-o | other), socket_path or endpoint, version, api_version.
container-image
An immutable container image (OCI image, LXC image, etc.).
| Field | Value |
|---|---|
| Kind | physical |
| Sandbox strategy | none (images are immutable) |
| User-addable | yes |
| CLI arguments | --image-ref (required, e.g., python:3.12-slim), --digest (optional), --engine-type (optional, inherited from parent runtime) |
| Allowed parents | container-runtime (1) |
| Allowed children | container-instance (0..*, instances created from this image) |
| Auto-discovery | Discovered from container-runtime. Does not auto-discover children (instances are discovered from the runtime). |
| Capabilities | read: true, write: false, sandbox: false, checkpoint: false |
Properties: image_ref, digest, engine_type, architecture, os, size_bytes, created_at, labels (key-value).
container-instance
A container — running, stopped, paused, or created.
| Field | Value |
|---|---|
| Kind | physical |
| Sandbox strategy | snapshot |
| User-addable | yes |
| CLI arguments | --container-id (optional), --name (optional), --image-ref (optional, links to parent image), --engine-type (optional, inherited from parent runtime) |
| Allowed parents | container-runtime (1), container-image (0..1, the image it was created from) |
| Allowed children | container-mount (0..*), container-exec-env (1), container-port (0..*) |
| Auto-discovery | Discovered from container-runtime. Auto-discovers mounts, execution environment, and port mappings. |
| Capabilities | read: true, write: true, sandbox: true, checkpoint: true |
Properties: container_id, name, state (running | stopped | paused | created | restarting | removing | dead), image_ref, engine_type, pid, created_at, labels (key-value), hostname, working_dir.
The snapshot sandbox strategy for container instances creates a container checkpoint or commit (engine-dependent), allowing rollback to a known state. For Docker/Podman this uses docker commit or docker checkpoint; for LXC/LXD this uses LXD snapshots.
container-mount
A mount point mapping external storage into a container.
| Field | Value |
|---|---|
| Kind | physical |
| Sandbox strategy | (inherits from container-instance parent) |
| User-addable | no (auto-discovered from container-instance) |
| Allowed parents | container-instance (1) |
| Allowed children | fs-directory (0..1, the mounted content root), fs-file (0..*, if a single file is mounted) |
| Auto-discovery | Discovered from container-instance by inspecting container mount configuration. Auto-discovers the mounted filesystem contents as fs-directory / fs-file children. |
| Capabilities | read: true, write: (depends on mount read_only flag), sandbox: (inherits), checkpoint: (inherits) |
Properties: source (host path, volume name, or tmpfs), target (container-internal path), mount_type (bind | volume | tmpfs | npipe), read_only, propagation (rprivate | private | rshared | shared | rslave | slave).
Virtual equivalence: When mount_type is bind, the fs-directory or fs-file children inside the container are equivalent to the corresponding fs-directory or fs-file resources on the host. They share the same directory or file virtual parent. The coherence property on this equivalence link is transparent — changes on either side are immediately visible to the other because they share the same underlying storage.
When mount_type is volume, the filesystem contents are independent of the host filesystem (unless the volume is backed by a host directory, in which case it behaves like a bind mount). Coherence: independent by default, transparent if the volume driver provides pass-through semantics.
container-volume
A named volume managed by the container engine.
| Field | Value |
|---|---|
| Kind | physical |
| Sandbox strategy | snapshot |
| User-addable | yes |
| CLI arguments | --volume-name (required), --driver (optional, default: local), --engine-type (optional, inherited from parent runtime) |
| Allowed parents | container-runtime (1) |
| Allowed children | fs-directory (0..1, root of volume contents) |
| Auto-discovery | Discovered from container-runtime. Auto-discovers the root directory of the volume. |
| Capabilities | read: true, write: true, sandbox: true, checkpoint: true |
Properties: volume_name, driver, mount_point (host path where volume data is stored), engine_type, labels (key-value), scope (local | global).
container-exec-env
The execution environment inside a container — what is available to run.
| Field | Value |
|---|---|
| Kind | physical |
| Sandbox strategy | (inherits from container-instance parent) |
| User-addable | no (auto-discovered from container-instance) |
| Allowed parents | container-instance (1) |
| Allowed children | executable (0..*) |
| Auto-discovery | Discovered from container-instance. Auto-discovers executables by scanning the container's PATH directories. |
| Capabilities | read: true, write: false, sandbox: (inherits), checkpoint: (inherits) |
Properties: path_dirs (list of PATH entries), env_vars (key-value environment variables), shell (default shell path), os (linux | windows | macos), architecture (amd64 | arm64 | ...), user (default user), working_dir.
This resource type answers the question: "What can I run in this container?" It is the foundation for tool and LSP server dependency resolution — by discovering what executables are available, the system can determine whether a particular tool or LSP server can run inside a given container.
container-network
A container network configuration.
| Field | Value |
|---|---|
| Kind | physical |
| Sandbox strategy | none |
| User-addable | no (auto-discovered from container-runtime) |
| Allowed parents | container-runtime (1) |
| Allowed children | (none) |
| Auto-discovery | Discovered from container-runtime. |
| Capabilities | read: true, write: false, sandbox: false, checkpoint: false |
Properties: network_name, driver (bridge | host | overlay | macvlan | none), subnet, gateway, scope (local | swarm | global).
container-port
A port mapping exposing a container port to the host.
| Field | Value |
|---|---|
| Kind | physical |
| Sandbox strategy | (inherits from container-instance parent) |
| User-addable | no (auto-discovered from container-instance) |
| Allowed parents | container-instance (1) |
| Allowed children | (none) |
| Auto-discovery | Discovered from container-instance. |
| Capabilities | read: true, write: false, sandbox: (inherits), checkpoint: (inherits) |
Properties: container_port, host_port, host_ip, protocol (tcp | udp | sctp).
Execution Environment Layer (1 type)
executable
A binary, script, or interpreter available in some execution environment.
| Field | Value |
|---|---|
| Kind | physical |
| Sandbox strategy | none (executables themselves are not sandboxed; the environment they run in is) |
| User-addable | yes |
| CLI arguments | --path (required, path to the executable), --name (optional, defaults to filename), --version (optional) |
| Allowed parents | container-exec-env (0..1, if inside a container), fs-directory (0..1, if on host filesystem) |
| Allowed children | (none) |
| Auto-discovery | Discovered from container-exec-env (scanning container PATH) or from fs-directory (scanning host PATH). |
| Capabilities | read: true, write: false, sandbox: false, checkpoint: false |
Properties: path (absolute path within the execution environment), name (the executable name, e.g., node, python3, pylsp), version (if detectable), interpreter (for scripts: python, bash, node, etc.), content_hash (SHA-256 of the binary).
Virtual equivalence: The same executable installed in multiple locations (host, multiple containers) can share a file virtual parent when the content hash matches. This enables the query: "Where else is this executable available?"
Tool dependency relationship: Tools and LSP servers declare dependencies on executables via references edges. A tool that requires node v18+ has a references edge to the executable resource for node. The system can then query: "Which container-exec-env or host fs-directory contains a node executable matching the version constraint?"
Containment Hierarchy Summary
container-runtime (docker/podman/containerd/lxc/lxd/cri-o)
├── container-image
│ └── (instances created from this image link back)
├── container-instance
│ ├── container-mount
│ │ ├── fs-directory ──[virtual equivalence]──▷ directory (virtual)
│ │ └── fs-file ──[virtual equivalence]──▷ file (virtual)
│ ├── container-exec-env
│ │ └── executable ──[virtual equivalence]──▷ file (virtual)
│ └── container-port
├── container-volume
│ └── fs-directory
└── container-network
Sandbox Domain Impact
Container resource types create new sandbox domains in the DAG:
| Sandbox Boundary | Strategy | Domain Contents |
|---|---|---|
container-instance |
snapshot |
All mounts, exec-env, ports, and their descendants within the container |
container-volume |
snapshot |
The volume's filesystem contents |
These domains are separate from host filesystem sandbox domains. When a bind mount creates virtual equivalence between container files and host files, the files exist in two different sandbox domains simultaneously. This is the primary use case for the cross-mechanism coordination protocol defined in ADR-038.
Engine-Specific Behavior
The container-runtime handler dispatches to engine-specific sub-handlers based on engine_type:
| Engine | Discovery | Instance Management | Snapshot Mechanism |
|---|---|---|---|
| Docker | Docker Engine API / docker CLI |
docker inspect, docker ps |
docker commit, docker checkpoint (experimental) |
| Podman | Podman API / podman CLI |
podman inspect, podman ps |
podman commit, podman container checkpoint |
| containerd | containerd API / ctr CLI |
ctr containers list |
ctr snapshots |
| LXC/LXD | LXD REST API / lxc CLI |
lxc list, lxc info |
lxc snapshot |
| CRI-O | CRI gRPC API | crictl ps, crictl inspect |
Engine-dependent |
The engine-specific details are encapsulated in the resource handler — the rest of the system interacts with the engine-agnostic resource types.
Constraints
- All container resource types must work with any engine type. Engine-specific behavior is encapsulated in the handler, not exposed in the resource type or DAG structure.
container-exec-envauto-discovery (scanning PATH for executables) may be expensive for containers with large PATH directories. Discovery should be lazy (triggered on demand or when a tool dependency needs resolution) rather than eager.container-mountequivalence with host files requires the system to resolve bind mount source paths to registered host resources. If the host directory is not registered as a resource, no equivalence link is created.container-instancesnapshot sandbox strategy depends on engine support. Not all engines support checkpointing (e.g., Docker checkpoint is experimental). When checkpointing is unavailable, the system falls back tononestrategy with a warning.
Consequences
Positive
- Container environments become first-class citizens in the resource DAG, enabling tool dependency resolution, sandbox coordination, and equivalence tracking across host and container boundaries.
- Engine-agnostic types ensure the system works with Docker, Podman, LXC/LXD, and any future container runtime without structural changes.
- The
executabletype enables answering "where can I run this tool?" — a critical question for heterogeneous environments.
Negative
- Nine new resource types (including
container-portandcontainer-network) add complexity to the type registry and documentation. - Container discovery requires engine-specific handler implementations for each supported engine.
- Executable discovery (scanning PATH) adds overhead and may produce large numbers of auto-discovered resources.
Risks
- Container state is volatile — instances can be stopped/removed externally without the system knowing. Resource staleness detection and cleanup are critical.
- Bind mount detection requires inspecting container configuration, which may require elevated privileges or engine API access.
- Snapshot-based sandboxing for containers may be slow for large container filesystems.
Alternatives Considered
Docker-only resource types — Simpler but locks the system to one engine. The container ecosystem has multiple viable engines, and users working with Podman, LXC/LXD, or containerd would be excluded.
No container resource types (external tool management only) — Treats containers as opaque external environments. Tools running in containers would be modeled as MCP servers with no visibility into the container's internals. This prevents tool dependency resolution and cross-mechanism equivalence tracking.
Compliance
- Type registration tests: Each new resource type validates correctly (CLI args, parent/child constraints, capabilities).
- Auto-discovery tests: Container runtime discovery correctly identifies instances, images, volumes, networks for at least Docker and Podman.
- Mount equivalence tests: Bind mount files correctly link to host files through virtual parents with
transparentcoherence. - Executable discovery tests: Container exec-env scanning correctly identifies executables and links them to
filevirtual parents when content hashes match host executables. - Engine abstraction tests: The same test suite runs against Docker and Podman handlers to verify engine-agnostic behavior.
Related ADRs
| ADR | Title | Relationship |
|---|---|---|
| ADR-008 | Resource System | These types extend the built-in resource type registry |
| ADR-036 | Resource DAG Operational Semantics | Container types create new sandbox domains subject to the sandbox boundary algebra |
| ADR-038 | Cross-Mechanism Sandbox Coordination | Container/host equivalence is the primary use case for cross-mechanism coordination |
| ADR-040 | LSP Resource Types | LSP servers may run inside containers, referencing container executables |
Acceptance
Votes For
| Voter | Comment |
|---|---|
| Jeffrey Phillips Freeman Jeffrey.Freeman@CleverThis.com | Engine-agnostic container types with executable discovery enable tool dependency resolution and cross-mechanism coordination |
Total: 1
Votes Against
| Voter | Comment |
|---|
Total: 0
Abstentions
| Voter | Comment |
|---|
Total: 0