Dependency Resolution
Relevant source files
The following files were used as context for generating this wiki page:
Dependency resolution in OCX is a multi-layered system designed to orchestrate the installation of AI components, npm plugins, and configuration settings across distributed registries and local environments. It ensures that all required assets for an OpenCode extension are identified, fetched in the correct order, and merged into the user's workspace while maintaining architectural integrity through strict validation and "Elegant Defense" principles.
The system handles three primary resolution flows:
- Registry Component Resolution: Navigating cross-namespace dependencies between components (e.g.,
kdco/workspacerequiringkdco/researcher). - Configuration Resolution: Merging global profiles, local project settings, and component-provided configurations in a deterministic cascade.
- Instruction Discovery: Identifying and filtering documentation files (like
AGENTS.md) based on project-relative paths and glob patterns.
Sources: packages/cli/src/registry/resolver.ts, packages/cli/src/config/resolver.ts, README.md
Registry Dependency Management
Registry resolution is responsible for taking a list of requested components and building a complete, ordered installation list. It utilizes a topological sort algorithm to ensure that dependencies are always processed before the components that rely on them.
Resolution Logic and Data Flow
The core logic resides in resolveDependencies, which performs a depth-first traversal of the dependency graph. It supports cross-namespace references where a component in one registry can depend on a component in another.
The diagram shows the flow from initial CLI input to the final sorted dependency object.
Sources: packages/cli/src/registry/resolver.ts:67-154, packages/cli/src/commands/add.ts:107-133
Key Data Structures
The resolver produces a ResolvedDependencies object containing everything needed for the installation phase.
| Property | Type | Description |
|---|---|---|
components | ResolvedComponent[] | Normalized manifests in topological order. |
installOrder | string[] | Ordered list of qualified component names. |
npmDependencies | string[] | Aggregated production dependencies from all components. |
npmDevDependencies | string[] | Aggregated development dependencies. |
opencode | OpencodeConfig | Deep-merged configuration from all resolved components. |
Sources: packages/cli/src/registry/resolver.ts:54-65
Validation and Safety
The system implements several "Elegant Defense" checks during resolution:
- Cycle Detection: A
visitingSet tracks active recursions to throw aValidationErrorif circular dependencies (e.g., A β B β A) are detected. Sources: packages/cli/src/registry/resolver.ts:88-92, packages/cli/tests/resolver.test.ts:79-85 - Namespace Enforcement: Components must include a namespace (e.g.,
kdco/agent) unless a default namespace is provided in context. Sources: packages/cli/src/registry/resolver.ts:25-42 - Integrity Verification: During the installation phase, fetched components are verified against SHA-256 hashes stored in the
ocx.lockfile. Sources: packages/cli/src/commands/add.ts:340-345, README.md:57-68
Configuration Cascade Resolution
The ConfigResolver handles the complex merging of settings from global profiles, local project directories, and environmental overrides.
The Resolution Cascade
OCX follows a specific priority order for configuration values, where later sources override earlier ones:
- Default Values: Base system defaults (e.g.,
.opencodeas the default component path). - Global Profile: Settings from
~/.config/opencode/profiles/<name>/ocx.jsonc. - Local Project Config: Settings from
./.opencode/ocx.jsonc(if not excluded by the profile).
This diagram illustrates the priority levels and decision points for configuration merging.
Sources: packages/cli/src/config/resolver.ts:162-211
Key Resolution Components
- Profile Resolution: Priority is given to the
--profileflag, followed by theOCX_PROFILEenvironment variable, and finally the "default" profile. Sources: packages/cli/src/config/resolver.ts:145-156, README.md:120-125 - Deep Merging: Objects are recursively merged, while arrays and scalar values follow "last-write-wins" logic. Sources: packages/cli/src/config/resolver.ts:394-416
- Origin Tracking: For debugging, the resolver can track the exact file path and source category (e.g., "global-profile") for every merged setting. Sources: packages/cli/src/config/resolver.ts:217-269
Instruction File Discovery
Instruction files (e.g., AGENTS.md, CLAUDE.md) are resolved by walking up the directory tree from the current working directory to the git root.
Discovery Algorithm
- Walk Up: The system starts at the current project directory and traverses parent directories until it reaches the git root (detected via
.gitpresence). Sources: packages/cli/src/config/resolver.ts:68-100 - Pattern Filtering: Discovered files are filtered through glob patterns defined in the
excludeandincludesections of the active profile. Sources: packages/cli/src/config/resolver.ts:114-131 - Priority Injection: Profile-specific instructions are appended at the end of the list, giving them the highest priority in the final OpenCode session. Sources: packages/cli/src/config/resolver.ts:373-390
Filtering Rules
OCX uses a TypeScript/Vite-style include/exclude model:
- Include overrides Exclude: If a file matches an include pattern, it is kept even if it matches an exclude pattern.
- Deepest First: Files are collected from the project directory up to the root, ensuring local instructions take precedence over root-level ones before profile instructions are added.
Sources: packages/cli/src/config/resolver.ts:114-131, README.md:175-207
Summary
Dependency resolution in OCX provides a robust foundation for building modular AI environments. By combining topological sorting for registry components with a deterministic configuration cascade and context-aware instruction discovery, the system ensures that complex AI extensions can be installed and managed with high predictability and security. The "Elegant Defense" implementation, particularly through early exits and boundary parsing, maintains system stability even when dealing with distributed registry data and conflicting local/global configurations.