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
286 lines
12 KiB
Markdown
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)
|