-
Notifications
You must be signed in to change notification settings - Fork 0
Dependency Resolution
How core resolves the load order of extensions that declare dependencies on each other, and how it rejects configurations that cannot be satisfied.
contractVersion: 1.0.0
Dependency Resolution runs after Validation Pipeline passes for each extension and before init. A validated-but-unresolvable extension (depends on something missing) produces a dependency diagnostic, not a validation diagnostic.
An extension's contract may declare:
classDiagram
class Dependencies {
dependsOn : List~Ref~
conflictsWith : List~Ref~
optionalCapabilities : List~Ref~
}
class Ref {
kind : Category
name : string
capability : string
}
Dependencies --> Ref
| Field | Meaning |
|---|---|
dependsOn |
The extension will not function without the referenced extension. Load order: dependency first. |
conflictsWith |
The extension will not function if the referenced extension is also loaded. |
optionalCapabilities |
The extension benefits from a referenced capability but runs without it. |
References are by { kind, name } or { kind, capability }. Capability-based references match any extension in the kind that advertises the capability.
flowchart TD
Validated[validated set] --> Build[build dependency graph]
Build --> Cycle{cycle<br/>detected?}
Cycle -->|yes| FailCycle["reject: cycle"]
Cycle -->|no| Conflict{conflict<br/>pair loaded?}
Conflict -->|yes| FailConflict["reject: conflict"]
Conflict -->|no| Missing{required<br/>dep missing?}
Missing -->|yes| FailMissing["reject: missing"]
Missing -->|no| Topo[topological sort]
Topo --> Order["init order: deps first"]
Cycles fail the session with a clear diagnostic — the wiki does not permit silent topological-break heuristics.
A conflictsWith pair that is mutually loaded fails one of the two. Which one loses is deterministic:
- Layer priority. A project-scope extension wins over a global one; global wins over bundled.
- Tiebreaker within a layer. The extension discovered earlier by Extension Discovery order wins.
The loser is rejected with a DependencyConflict diagnostic naming the winner.
A dependsOn reference that resolves to zero loaded extensions rejects the dependent extension.
| Severity | Posture |
|---|---|
The dependent is itself critical
|
Hard-fail the session. |
The dependent is optional
|
Skip the dependent with a warning; continue. |
Missing optionalCapabilities never fail anything — they are informational. An extension that cares whether a capability is present checks at runtime; the dependency graph tracks it only for diagnostics.
Topological sort (Kahn's algorithm) produces the init order. The sort is deterministic: when multiple extensions are eligible to init at the same step (zero unsatisfied dependencies), they are admitted in lexicographic order by extId. This guarantees that the same extension set always produces the same initOrder regardless of the order in which declarations are presented.
disposeOrder is always the exact reverse of initOrder. Dependents shut down before their dependencies in every context — normal session teardown, graceful reload, and error recovery.
Extensions without any dependsOn entries init in lexicographic extId order among the other zero-degree nodes at the front of the queue.
Within a category, load order influences nothing except init timing. The activation order for ordered categories (Hooks) follows the ordering manifest, not the dependency graph. See Hooks.
A reload that changes the extension set re-runs dependency resolution. A reload that would introduce a conflict or break a dependency rejects the reload; the previous extension set stays active. See Extension Reloading.
A graceful reload re-orders deactivate in reverse of the current topological order (i.e. disposeOrder) so that dependents shut down before their dependencies.
A failed resolution produces one of:
| Code | Meaning |
|---|---|
DependencyCycle |
Two or more extensions depend on each other transitively. |
DependencyMissing |
A dependsOn reference has no matching loaded extension. |
DependencyConflict |
Two extensions declare mutual conflictsWith. |
Each carries the involved extensions' identifiers and the cycle path or conflict target. Diagnostics land on the event bus and in the Audit Trail.
The resolved dependency graph is recorded in the session manifest: for each loaded extension, the list of dependencies it required at load time. Resume verifies the same graph resolves against the current extension set; drift on a resumed dependency follows the same rules as drift on a state slot (see Extension State).
- Dependency declarations are trust input. A malicious project may declare a dependency on a well-known security hook and then conflict it away, effectively disabling the hook. Project trust is the guard — see Project Trust.
- Optional-capability probing is not a channel for side effects. An extension that reads another extension's state as a "capability check" is a bug. Dependency resolution is structural only.
- Dependency Resolution spec as documented above.
dependsOn/conflictsWith/optionalCapabilitiesdeclarations; topological load ordering; structural-only resolution.
- Execution Model
- Message Loop
- Concurrency and Cancellation
- Error Model
- Event and Command Ordering
- Event Bus
- Command Model
- Interaction Protocol
- Hook Taxonomy
- Host API
- Extension Lifecycle
- Env Provider
- Prompt Registry
- Resource Registry
- Session Lifecycle
- Session Manifest
- Persistence and Recovery
- Stage Executions
- Subagent Sessions
- Contract Pattern
- Versioning and Compatibility
- Deprecation Policy
- Capability Negotiation
- Dependency Resolution
- Validation Pipeline
- Cardinality and Activation
- Extension State
- Conformance and Testing
- Providers
- Provider Params
- Tools
- Hooks
- UI
- Loggers
- State Machines
- SM Stage Lifecycle
- Stage Definitions
- Commands
- Session Store
- Context Providers
- Settings Shape
- Trust Model
- Project Trust
- Extension Isolation
- Extension Integrity
- LLM Context Isolation
- Secrets Hygiene
- Security Modes
- Tool Approvals
- MCP Trust
- Sandboxing
- Configuration Scopes
- Project Root
- Extension Discovery
- Extension Installation
- Extension Reloading
- Headless and Interactor
- Determinism and Ordering
- Launch Arguments
- Network Policy
- Platform Integration
Tools
UI
Session Stores
Loggers
Providers
Hooks
Context Providers
Commands
- First Run
- Default Chat
- Tool Call Cycle
- Hook Interception
- Guard Deny Reproposal
- State Machine Workflow
- SM Stage Retry
- Hot Model Switch
- Capability Mismatch Switch
- Session Resume
- Session Resume Drift
- Approval and Auth
- Interaction Timeout
- Headless Run
- Parallel Tool Approvals
- Subagent Delegation
- Scope Layering
- Project First-Run Trust
- Reload Mid-Turn
- Compaction Warning
- MCP Remote Tool Call
- MCP Prompt Consume
- MCP Resource Bind
- MCP Reconnect