- docs/api/actor.md: Add InvariantReconciliationActor section documenting the built-in reconciliation actor introduced in v3.8.0, including the reconciliation algorithm, ReconciliationResult/ConflictRecord/ScopeInvariants data classes, standalone reconcile_invariants() function, DI registration, and failure behaviour. - docs/modules/devcontainer-discovery.md: New module guide for the devcontainer auto-discovery system (v3.8.0 fix #2615), covering DevcontainerDiscoveryResult, discover_devcontainers(), is_trigger_type(), monorepo named-config support, and gotchas. - mkdocs.yml: Add 'Devcontainer Auto-Discovery' to the Modules nav section, alongside shell-safety, uko-provenance, invariant-reconciliation, context-hydration, and git-worktree-sandbox module docs. - robot/coverage_threshold.robot: Add tdd_issue and tdd_issue_4305 tags to the Noxfile Contains Coverage Threshold Constant test case. ISSUES CLOSED: #4485
5.4 KiB
Devcontainer Auto-Discovery
Package: cleveragents.resource.handlers.discovery
Introduced: v3.8.0 (issue #2615)
This module guide covers the devcontainer auto-discovery system, which
automatically detects devcontainer.json configurations when a
git-checkout or fs-directory resource is linked to a project.
It supports both root-level configurations and named configurations
for monorepo projects.
Purpose
When a git-checkout or fs-directory resource is registered, the
discover_devcontainers() function scans the resource location for
devcontainer.json files. Each valid configuration is returned as a
DevcontainerDiscoveryResult, which the resource registry uses to
create child devcontainer-instance resources automatically.
Scan Paths
The scanner checks three categories of paths:
| Category | Path | config_name |
|---|---|---|
| Root-level (default) | .devcontainer/devcontainer.json |
None |
| Root-level (flat) | .devcontainer.json |
None |
| Named configuration | .devcontainer/<name>/devcontainer.json |
"<name>" |
Named configurations are discovered by iterating one subdirectory level
inside .devcontainer/. Each subdirectory that contains a
devcontainer.json produces a separate result with config_name set to
the subdirectory name (e.g. "api", "frontend").
Key Classes and Functions
DevcontainerDiscoveryResult
from cleveragents.resource.handlers.discovery import DevcontainerDiscoveryResult
result = DevcontainerDiscoveryResult(
config_path=Path("/workspace/.devcontainer/api/devcontainer.json"),
config_data={"name": "API Dev Container", "image": "mcr.microsoft.com/devcontainers/python:3.12"},
parent_location="/workspace",
config_name="api",
)
| Attribute | Type | Description |
|---|---|---|
config_path |
Path |
Absolute path to the devcontainer.json file |
config_data |
dict[str, object] |
Parsed JSON content of the devcontainer config |
parent_location |
str |
Filesystem path of the parent resource |
config_name |
str | None |
Named configuration identifier, or None for root-level configs |
discover_devcontainers
from cleveragents.resource.handlers.discovery import discover_devcontainers
results = discover_devcontainers(
resource_location="/workspace",
resource_type="git-checkout",
)
for result in results:
print(result.config_name, result.config_path)
Scans a resource location for all valid devcontainer configurations. Invalid JSON files are skipped with a warning log rather than raising.
Parameters:
| Parameter | Type | Description |
|---|---|---|
resource_location |
str |
Filesystem path of the parent resource |
resource_type |
str |
Type name of the parent resource |
Returns: list[DevcontainerDiscoveryResult] — one entry per valid config.
Raises:
ValueError— ifresource_locationis empty orresource_typeis empty/blank.
is_trigger_type
from cleveragents.resource.handlers.discovery import is_trigger_type
is_trigger_type("git-checkout") # True
is_trigger_type("sqlite") # False
Returns True if the given resource type triggers devcontainer auto-discovery.
Currently only "git-checkout" and "fs-directory" are trigger types.
Monorepo Example
Given a monorepo with the following layout:
/workspace/
├── .devcontainer/
│ ├── api/
│ │ └── devcontainer.json → config_name="api"
│ └── frontend/
│ └── devcontainer.json → config_name="frontend"
└── src/
discover_devcontainers("/workspace", "git-checkout") returns two results:
results = discover_devcontainers("/workspace", "git-checkout")
# results[0].config_name == "api"
# results[1].config_name == "frontend"
Each result produces a distinct devcontainer-instance resource in the
registry, allowing plans to target individual containers by name.
Root-Level Example
For a single-container project:
/workspace/
├── .devcontainer/
│ └── devcontainer.json → config_name=None
└── src/
results = discover_devcontainers("/workspace", "git-checkout")
# results[0].config_name is None
Root-level configs retain config_name=None for full backward compatibility.
Gotchas
- Non-trigger types return an empty list. Calling
discover_devcontainers()with a resource type that is not"git-checkout"or"fs-directory"returns[]immediately without scanning the filesystem. - Invalid JSON is silently skipped. Files that cannot be parsed as JSON
objects are logged at
WARNINGlevel and excluded from results. - Only one subdirectory level is scanned. Named configurations must be
directly inside
.devcontainer/<name>/devcontainer.json. Deeper nesting is not supported. - Sorted order. Named configurations are returned in lexicographic order
of their subdirectory names (via
sorted(dc_dir.iterdir())).
Related Documentation
- Resource System API —
ResourceHandlerprotocol and built-in handlers - ADR-043 Devcontainer Integration — design rationale
- Resource System —
DevcontainerHandlerCRUD operations