Files
cleveragents-core/docs/reference/resource_dag.md
T
freemo e28f9a8597 Docs: Add resource DAG operational semantics, tool reachability, cross-mechanism coordination, container, and LSP resource type ADRs (036-040)
- 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
2026-02-21 19:51:28 -05:00

6.9 KiB

Resource DAG

Resources in CleverAgents form a directed acyclic graph (DAG) where parent resources contain or reference child resources. This document describes the linking rules, cycle detection, type compatibility enforcement, and auto-discovery behaviour.

DAG Rules

Rule Description
No self-loops A resource cannot be its own child.
No cycles If resource A is an ancestor of B, then B cannot become a parent of A.
Type compatibility The child's resource type must appear in the parent type's child_types list.
Unique links A given (parent, child) pair can only be linked once.
Both must exist Both the parent and the child resource must be registered before linking.

API

Links a child resource to a parent in the DAG.

  1. Validates that both resources exist in the registry.
  2. Checks type compatibility — the child resource's type must be listed in the parent resource type's child_types field.
  3. Performs cycle detection — walks the ancestor chain of the parent to ensure the child is not already an ancestor.
  4. Persists the link in the resource_links table.

Errors:

  • ResourceNotFoundRepoError — parent or child does not exist.
  • TypeIncompatibleError — child type not in parent's child_types.
  • CycleDetectedError — linking would create a cycle.
  • DuplicateResourceLinkError — link already exists.

Removes a parent-child link from the DAG.

  1. Validates that both resources exist.
  2. Validates the link exists.
  3. Deletes the link from resource_links.

Errors:

  • ResourceNotFoundRepoError — parent or child does not exist.
  • LinkNotFoundError — the link does not exist.

get_children(resource_id)

Returns all direct children of a resource (via resource_links).

get_parents(resource_id)

Returns all direct parents of a resource (via resource_links).

Cycle Detection

Cycle detection uses a breadth-first search upward through the resource_links table starting from the proposed parent. If the proposed child is found among the ancestors, the link is rejected with a CycleDetectedError that includes the cycle path.

Example

A -> B -> C

Attempting to link C -> A would be rejected because A is an ancestor of C. The error message includes the path: A -> B -> C -> A.

Type Compatibility

Each resource type defines a child_types list of allowed child type names. When linking, the system verifies:

child.resource_type_name in parent_type.child_types

If the parent type's child_types list is empty, any child type is allowed (no restriction).

Example

# git-checkout type
child_types: ["fs-directory", "git"]

Only resources of type fs-directory or git can be linked as children of a git-checkout resource.

Auto-Discovery

auto_discover_children(resource_id)

Materializes child resources based on the parent's type auto-discovery configuration.

  1. Looks up the resource and its type.
  2. Reads the auto_discovery configuration from the type.
  3. For each discovery rule where enabled is true:
    • Checks the child type exists in the database.
    • Checks type compatibility with the parent.
    • Creates a new child resource with auto_discovered = true.
    • Links the child to the parent via resource_links.
  4. Returns the list of newly created child resources.

Auto-Discovery Configuration

Auto-discovery is configured per resource type in YAML:

auto_discovery:
  enabled: true
  rules:
    - type: fs-directory
      pattern: "*/"
    - type: fs-file
      pattern: "*"

Each rule specifies:

  • type — the child resource type name to create.
  • pattern — a glob pattern (used by handlers for actual file discovery; the repository layer creates placeholder entries).

When Does Auto-Discovery Run?

Auto-discovery is triggered by calling auto_discover_children(resource_id). This is typically invoked:

  • When a resource is first registered.
  • When a resource's contents change (e.g., new files appear).
  • On demand via CLI commands.

Database Schema

Column Type Description
parent_id String(26) FK to resources.resource_id
child_id String(26) FK to resources.resource_id
created_at String(30) ISO-8601 timestamp

Primary key: (parent_id, child_id)

Constraints:

  • parent_id != child_id (no self-loops)
  • Foreign keys cascade on delete

resource_edges Table (Extended)

Column Type Description
parent_id String(26) FK to resources.resource_id
child_id String(26) FK to resources.resource_id
link_type String(20) contains, references, or physical-to-virtual
auto_discovered Boolean Whether the link was auto-discovered
coherence String(20) transparent, cached, independent, or NULL (only set on physical-to-virtual edges)
created_at String(30) ISO-8601 timestamp

Operational Semantics

Beyond structural rules, the DAG supports runtime operations. For full details, see ADR-036, ADR-037, and ADR-038.

Sandbox Boundary Algebra

  • sandbox_boundary(r): Nearest sandboxable ancestor of r along contains edges.
  • Sandbox domain: All resources sharing the same sandbox boundary share one sandbox instance.
  • Resources below a boundary (e.g., files within a git-checkout) cannot be sandboxed independently.

Tool Reachability

  • Forward: Tool bound to R can reach R and all contains descendants.
  • Inverse: Resource r is reachable by tools bound to any of r's containment ancestors.
  • Cross-equivalence: Tools reaching one physical manifestation of a virtual resource also logically reach all equivalent manifestations.

Access Projection

Each resource type handler implements project_access() to compute how a tool bound to an ancestor reaches a descendant resource (access path, protocol, sandbox-crossing awareness, read richness score).

Read/Write Routing

Virtual resources with multiple physical manifestations route:

  • Reads through the richest available source (LSP > filesystem > raw).
  • Writes through the canonical write target (strongest sandbox domain).

Cross-Mechanism Coordination

  • Coherence: transparent (shared storage), cached (needs refresh), independent (needs sync).
  • Write-then-sync: Changes propagate at commit time, not during execution.
  • Conflict detection: Multiple dirty manifestations of the same virtual resource at commit time trigger resolution (canonical-wins, merge, fail, or last-writer-wins).