Files
cleveragents-core/docs/reference/devcontainer_resources.md
T
freemo d5b122d4a3
CI / lint (push) Successful in 14s
CI / quality (push) Successful in 21s
CI / security (push) Successful in 36s
CI / build (push) Successful in 36s
CI / typecheck (push) Successful in 39s
CI / benchmark-regression (push) Has been skipped
CI / unit_tests (push) Successful in 2m57s
CI / integration_tests (push) Successful in 3m23s
CI / docker (push) Successful in 53s
CI / coverage (push) Successful in 5m58s
CI / benchmark-publish (push) Successful in 19m27s
Docs: Updated to A2A and integrating rest standard
2026-03-11 13:19:55 -04:00

286 lines
12 KiB
Markdown

# Devcontainer Resources
Devcontainer resources integrate the
[Development Containers Specification](https://containers.dev) into the
CleverAgents resource model. Two resource types and an auto-discovery
mechanism allow CleverAgents to detect, register, and use devcontainer
environments automatically.
## Resource Types
### `devcontainer-instance`
A container execution environment defined by a
`.devcontainer/devcontainer.json` configuration file. Inherits from
`container-instance` (see ADR-042 for resource type inheritance).
| Property | Value |
|-------------------|-----------------------|
| Kind | physical |
| Sandbox strategy | none (container provides isolation) |
| User-addable | yes |
| Parent types | git-checkout, fs-directory |
| Child types | devcontainer-file |
| Handler | `DevcontainerHandler` |
**CLI arguments:**
- `--path` (path, required): Path to the directory containing
`.devcontainer/devcontainer.json`.
### `devcontainer-file`
A single-file resource pointing to the `devcontainer.json`
configuration file itself. Created automatically as a child of
`devcontainer-instance` during auto-discovery.
| Property | Value |
|-------------------|-----------------------|
| Kind | physical |
| Sandbox strategy | copy\_on\_write |
| User-addable | no |
| Parent types | devcontainer-instance |
| Child types | (none) |
| Handler | `DevcontainerHandler` |
### `container-instance`
The base container resource type from which `devcontainer-instance`
inherits. Represents a generic container execution environment.
| Property | Value |
|-------------------|-----------------------|
| Kind | physical |
| Sandbox strategy | none (container provides isolation) |
| User-addable | yes |
| Parent types | git-checkout, fs-directory |
| Child types | (none) |
| Handler | `DevcontainerHandler` |
## Auto-Discovery (Planned)
> **Not yet wired (F31/F23):** The discovery module
> (`discover_devcontainers()`) exists and is tested in isolation, but
> is **not** invoked during `project link-resource` or any other
> production code path. Auto-discovery will be wired in a follow-up PR.
> For now, devcontainer-instance resources must be added manually via
> `agents resource add`.
When wired, linking a `git-checkout` or `fs-directory` resource to a
project will trigger an auto-discovery hook that scans for devcontainer
configurations in the following locations (relative to the resource
root):
1. `.devcontainer/devcontainer.json`
2. `.devcontainer.json` (root-level)
### Discovery Process (Planned)
1. **Trigger**: Linking a `git-checkout` or `fs-directory` resource.
2. **Scan**: The discovery module checks for configuration files at the
well-known paths listed above.
3. **Validate**: Each discovered file is parsed as JSON. Invalid files
are skipped with a warning.
4. **Register**: For each valid configuration:
- A `devcontainer-instance` child resource is created under the
parent resource.
- A `devcontainer-file` child resource is created under the
devcontainer instance, pointing to the JSON file.
### Lazy Activation
Devcontainers use lazy activation: the container is only built and
started when first needed by a plan execution. The discovery phase
only registers the resource metadata.
## Lifecycle Management
Devcontainer-instance resources support a full lifecycle state
machine with six states and validated transitions.
### State Diagram
```
detected ──► building ──► running ──► stopping ──► stopped
│ │
▼ │
failed ◄───────────────────────────────┘
│ ▲
└──► building │
(retry) (rebuild)
stopped ───────┘
```
### States
| State | Description |
|------------|---------------------------------------------------|
| `detected` | Container not yet started (default for new) |
| `building` | Container is being activated (`devcontainer up`) |
| `running` | Container is running and healthy |
| `stopping` | Container is being stopped |
| `stopped` | Container has been stopped cleanly |
| `failed` | Container is in an error state |
### Valid Transitions
| From | To | Trigger |
|-----------|---------------------|-----------------------|
| detected | building | lazy activation |
| building | running | `devcontainer up` OK |
| building | failed | `devcontainer up` fail|
| running | stopping | stop command |
| stopping | stopped | container stopped |
| stopping | failed | stop failed |
| stopped | building | rebuild |
| failed | building | retry |
### Lazy Activation Flow
When a tool targets a devcontainer-instance that is in `detected`
state:
1. Transition to `building`.
2. Run `devcontainer up --workspace-folder <location>`.
3. Parse JSON output for `containerId` and `remoteWorkspaceFolder`.
4. On success: transition to `running`.
5. On failure: transition to `failed`.
### Health Checking
> **Implementation-ahead-of-spec (SPEC-3):** Health checking and
> session-scoped cleanup are implemented but not yet formally specified
> in `docs/specification.md` for container resources (the spec only
> defines health checking for LSP servers). These features fulfil
> Issue #514 acceptance criteria and will be added to the specification
> in a follow-up PR.
Active containers receive periodic health probes. Health checking
starts automatically when a container transitions to `running` state
via `activate_container`.
- **Command**: `devcontainer exec ... echo ping`
- **Default interval**: 30 seconds (configurable via
`health_check_interval` on the lifecycle tracker).
- **On failure**: transitions to `failed` via `stopping`.
- Health checks run as background daemon threads.
- Health checks are stopped automatically before container stop.
### Session/Plan Cleanup
When a session closes or a plan completes/fails/is-cancelled, active
devcontainer-instances **scoped to that session or plan** are stopped
automatically. Each `ContainerLifecycleTracker` carries an optional
`session_id` field, set during activation, used to scope cleanup.
Cleanup is wired into the following hooks:
- `A2aLocalFacade._handle_session_close` — session close
- `PlanLifecycleService.complete_apply` — plan success
- `PlanLifecycleService.fail_apply` — plan apply failure
- `PlanLifecycleService.fail_execute` — plan execute failure
- `PlanLifecycleService.cancel_plan` — plan cancellation
```python
CleanupService.stop_active_devcontainers(session_id="...")
```
## CLI Usage
```bash
# Manually add a devcontainer instance
agents resource add devcontainer-instance local/my-dc --path /home/user/project
# Add a container instance
agents resource add container-instance local/my-ctr --image ubuntu:latest
# List all devcontainer resources
agents resource list --type devcontainer-instance
# Show devcontainer details
agents resource show local/my-dc
# View resource tree (shows devcontainer children)
agents resource tree local/my-repo
# Inspect resource with tree view
agents resource inspect local/my-repo --tree
# Stop an active devcontainer
agents resource stop local/my-dc
# Stop without confirmation prompt (for scripts)
agents resource stop local/my-dc --yes
# Rebuild a stopped or errored devcontainer
agents resource rebuild local/my-dc --yes
```
### Stop Command
```bash
agents resource stop <devcontainer-name> [--yes|-y]
```
Transitions an active container through `running → stopping → stopped`.
Only `devcontainer-instance` resources may be stopped (F19 fix:
`container-instance` was removed because it has no lifecycle tracker
wiring). Prompts for confirmation unless `--yes` (`-y`) is passed.
If the container is already in a terminal state (`stopped` or
`failed`), the stop is a no-op and returns immediately.
### Rebuild Command
```bash
agents resource rebuild <devcontainer-name> [--yes|-y]
```
Transitions a stopped or errored container through
`stopped/failed → building → running`. Runs `devcontainer up` to
rebuild the container. Only `devcontainer-instance` resources may
be rebuilt (not generic `container-instance`). Prompts for
confirmation unless `--yes` (`-y`) is passed.
## Known Limitations
| Limitation | Detail | Planned Fix |
|------------|--------|-------------|
| In-memory lifecycle state (F20) | Lifecycle state is tracked in an in-memory registry (`_lifecycle_registry` dict), **not** persisted on the resource model or database. State is lost on process restart. CLI `stop`/`rebuild` in a new process cannot see trackers from a previous process. | M7+: Persist `activation_state` on the resource model per the spec field definition, hydrating trackers on CLI operations. |
| Registry eviction | Terminal-state trackers (stopped/failed) are evicted when count exceeds 200 (`_MAX_TERMINAL_TRACKERS`). Eviction runs automatically after bulk cleanup via `stop_all_active_containers`. Long-running processes with many container cycles may lose historical tracker data. | Acceptable for MVP; persisted state in M7+ eliminates this. |
| Sandbox strategy (F22/F25) | Specification uses `container_snapshot`; `SandboxFactory` does not yet implement `snapshot`. Handler now uses `SandboxStrategy.NONE` — the container itself provides isolation. | Implement `container_snapshot` in `SandboxFactory` and switch handler back to it. |
| Hardcoded `docker stop` (F21) | `stop_container()` calls `docker stop` directly. Devcontainer CLI can target Podman or other engines; the devcontainer CLI does not yet offer a `stop` subcommand. | Detect the container engine from resource properties or devcontainer CLI config and dispatch to the appropriate stop command. |
| Auto-discovery not wired (F23) | Documentation describes auto-discovery on `project link-resource`, but no code path invokes `discover_devcontainers()` during resource linking. | Wire the discovery hook into the resource linking flow. |
| Container execution stubbed (F24) | `ToolRunner` returns an error for `ExecutionEnvironment.CONTAINER`, so lazy activation cannot trigger via tool use in production. Lazy activation currently works through `DevcontainerHandler.resolve()` on plan sandbox resolution. | Full container execution support is scoped for a follow-up PR (#616). |
## Architecture
The devcontainer integration follows ADR-043 and builds on the
resource type inheritance model defined in ADR-042.
### Handler
`DevcontainerHandler` extends `BaseResourceHandler` and uses the
`none` sandbox strategy (the container itself provides isolation).
For `devcontainer-instance` resources, the handler overrides
`resolve()` to trigger lazy activation via `activate_container()`
when the resource is in a non-running state. It handles both
`devcontainer-instance` and `devcontainer-file` resource types.
### Discovery Module
The `cleveragents.resource.handlers.discovery` module provides:
- `discover_devcontainers(location, type)`: Scans a path for
devcontainer configs.
- `is_trigger_type(type)`: Checks if a resource type triggers
auto-discovery.
- `DevcontainerDiscoveryResult`: Data class holding discovery results.
## See Also
- [ADR-042: Resource Type Inheritance](../adr/ADR-042-resource-type-inheritance.md)
- [ADR-043: Devcontainer Integration](../adr/ADR-043-devcontainer-integration.md)
- [Resource Types (Built-in)](resource_types_builtin.md)
- [Resource Handlers](resource_handlers.md)