Project Structure of Cordis: Modular Monorepo Architecture Explained

Cordis organizes its codebase as a Yarn workspace monorepo where each feature lives as an independent TypeScript package under packages/, with core providing the central runtime, loader handling dynamic module resolution, and hmr enabling hot-module replacement.

The Cordis project structure follows a strict modular design that separates concerns into discrete, composable units. As implemented in cordiverse/cordis, this monorepo architecture allows developers to import only the functionality they need while maintaining consistent TypeScript configuration across the entire codebase. The repository root houses standard configuration files alongside a packages/ directory containing nine distinct functional modules.

High-Level Repository Layout

The root directory contains standard CI and tooling configuration, while all source code resides within the packages/ workspace.


/ (repo root)
├─ .github/          – CI workflows
├─ .yarnrc.yml       – Yarn configuration
├─ .eslintrc.yml     – Linting rules
├─ tsconfig*.json    – TypeScript build configs
├─ vitest.config.ts  – Vitest test runner config
├─ package.json      – Workspace definition
└─ packages/
   ├─ core/          – Core runtime (loader, HMR, plugin API)
   ├─ loader/        – Dynamic module loader & isolation utilities
   ├─ hmr/           – Hot‑module‑replacement implementation
   ├─ logger-console – Console logger implementation
   ├─ timer/         – Simple timer utility
   ├─ utils/         – General-purpose utility functions
   ├─ include/       – Runtime code‑inclusion helpers
   ├─ group/         – Helpers for grouping plugins
   └─ create/        – Project scaffolding (currently empty)

Each package maintains its own tsconfig.json, package.json, and a tests/ folder containing Vitest unit tests.

Core Packages and Responsibilities

Core

The core package provides the central Cordis class that coordinates plugins and exposes the loader and HMR APIs. Located at packages/core/, this module serves as the primary entry point for applications. The main executable is packages/core/bin.js, which initializes the runtime environment.

Loader

The loader package at packages/loader/ implements a configurable module loader supporting isolation, dependency resolution, and hot reloading. The primary interface is packages/loader/src/index.ts, which exports the Loader class responsible for resolving plugin entry points and registering them with the core.

HMR

Located in packages/hmr/, the hot-module-replacement package supplies the logic that allows plugins to be swapped without restarting the host application. This enables development workflows where code changes propagate instantly while preserving application state when possible.

Supporting Utilities

  • logger-console: Provides simple console logging via packages/logger-console/src/browser.ts for debugging output.
  • timer: Offers scheduled callback functionality through the Timer class.
  • utils: Contains miscellaneous helpers like isObject and deepClone in packages/utils/src/index.ts.
  • include: Supplies runtime code-inclusion helpers that let plugins inject additional source files.
  • group: Utilities for organizing multiple plugins into logical groups, implemented in packages/group/src/index.ts.

Core Architecture and Data Flow

Understanding the Cordis project structure requires following the initialization sequence across packages:

  1. Initialization – The host application creates a Cordis instance from the core package.
  2. Loading – The loader resolves plugin entry points, isolates them in separate contexts, and registers them with the core runtime.
  3. HMR – When plugin files change, the hmr package swaps the old module for the new implementation without restarting the process.
  4. Utilities – Plugins leverage utils, timer, or logger-console for common tasks without external dependencies.

This modular layout enables tree-shaking and selective imports, allowing production applications to exclude unused functionality.

When exploring the Cordis repository, target these critical paths:

Each package follows the convention of placing source code in src/ and corresponding tests in tests/ using the .spec.ts suffix.

Working with the Cordis Project Structure

The following example demonstrates how the packages interact to load plugins dynamically:

import { Cordis } from 'cordis/core';
import { Loader } from 'cordis/loader';

// Create a loader that watches a directory for plugins
const loader = new Loader({
  root: './plugins',   // folder containing plugin entry files
  watch: true,         // enable HMR for changes
});

// Initialise Cordis with the loader
const cordis = new Cordis({ loader });

// Load all plugins
await cordis.loadAll();

// Now you can interact with the registered plugins
cordis.plugins.forEach(p => console.log(p.name));

This code imports from cordis/core and cordis/loader, reflecting the package boundaries within the monorepo. The Loader class resolves files from the filesystem while the Cordis instance manages the plugin lifecycle.

Summary

  • Cordis uses a Yarn workspace monorepo structure with nine specialized packages under packages/.
  • The core package provides the central Cordis class and plugin coordination APIs via packages/core/bin.js.
  • loader and hmr packages handle dynamic module resolution and hot reloading respectively.
  • Each package maintains independent TypeScript configuration, package.json, and Vitest test suites in tests/ directories.
  • Supporting packages like utils, timer, and logger-console provide isolated utility functions without external dependencies.

Frequently Asked Questions

What is the main entry point for the Cordis core package?

The primary entry point is packages/core/bin.js, which initializes the Cordis runtime and exposes the CLI interface. This file coordinates with the Loader class from packages/loader/src/index.ts to resolve and register plugins.

How does Cordis implement hot module replacement?

The hmr package located at packages/hmr/ contains the hot-module-replacement implementation. It monitors file changes and swaps plugin modules dynamically without requiring a full application restart, preserving state when the implementation allows.

Where are the unit tests located in the Cordis project structure?

Each package contains its own tests/ directory with Vitest unit tests using the .spec.ts extension. For example, loader tests reside in packages/loader/tests/ while utility tests are in packages/utils/tests/.

Which package manages plugin loading and isolation?

The loader package at packages/loader/ handles all dynamic module resolution. Its src/index.ts file exports the Loader class, which creates isolated contexts for plugins, resolves dependencies, and interfaces with the hmr system for reloading.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →