# Understanding the Cordis Fiber Class: Complete Guide to Plugin Lifecycle Management

> Master the Cordis Fiber class, the core object for plugin lifecycle management in cordiverse/cordis. Learn about instantiation, configuration, hot reloading, and disposal.

- Repository: [Cordiverse/cordis](https://github.com/cordiverse/cordis)
- Tags: deep-dive
- Published: 2026-09-12

---

**The Cordis Fiber class is the core runtime object in cordiverse/cordis that manages a plugin’s entire lifecycle—from instantiation and configuration to hot reloading and graceful disposal.**

The **Cordis Fiber** orchestrates how plugins execute within the Cordis framework. Defined in the `cordiverse/cordis` repository, this class encapsulates state management, effect registration, and the complex state machine that governs when a plugin is loading, active, or unloading. Understanding the Fiber is essential for building robust plugins that handle configuration changes and service dependencies correctly.

## What Is the Cordis Fiber Class?

The **Cordis Fiber class** represents a single instance of plugin execution within a Cordis application. Located in [`packages/core/src/fiber.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/fiber.ts), the `Fiber` class is instantiated by `Context.plugin()` and stored on the parent context as `ctx.fiber`.

Unlike simple function calls, a Fiber maintains persistent state across reloads. It tracks the plugin’s configuration, manages disposable side effects like timers and event listeners, and implements a formal state machine that transitions through `PENDING → LOADING → ACTIVE → UNLOADING → DISPOSED`. This architecture ensures that plugins can be safely reloaded without leaking resources or leaving orphaned asynchronous operations.

## Cordis Fiber Architecture and State Machine

### File Location and Construction

The Fiber implementation resides in [`packages/core/src/fiber.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/fiber.ts). When you call `ctx.plugin()`, the framework constructs a new `Fiber` instance (lines 22-36) with the following parameters:

- The parent `Context`
- The plugin’s resolved configuration
- An injection map for dependency tracking
- Runtime metadata
- A callback for generating outer stack traces

During construction, the Fiber creates a child context via `this.context = parent.extend({ fiber: this })` and registers itself in the parent’s registry. This linkage ensures that when the parent context shuts down, all child Fibers dispose automatically.

### The FiberState Lifecycle

The `Fiber` class uses the `FiberState` enum to track exactly where a plugin stands in its lifecycle (lines 78-84). The private `_getState()` and `_updateState()` methods (lines 48-62) transition between states based on the current epoch, error status, and disposal flags.

**Core lifecycle states:**
- **PENDING** – The Fiber is created but not yet executing
- **LOADING** – The plugin callback is currently running
- **ACTIVE** – The plugin is fully initialized and serving requests
- **UNLOADING** – The plugin is executing disposal logic
- **DISPOSED** – All effects have been cleaned up and the Fiber is inactive

A separate **FAILED** state occurs when `_error` is populated, preventing state transitions until `update()` clears the error condition (lines 224-227).

### Epoch Tracking and Reload Cycles

Cordis implements hot reloading through an **epoch** string that tracks which service implementations are currently satisfied. When injected dependencies change, the `_setEpoch()` method (lines 99-115) compares the new epoch against the current one.

If the epoch becomes `__INACTIVE__`, the Fiber triggers `_unload()` (lines 167-210) to dispose all effects. If valid services become available, `_reload()` executes the plugin callback again while preserving the implementation store and restoring disposable effects. This mechanism allows plugins to restart without losing their place in the dependency graph.

## Effect Management in Cordis Fiber

### Registering Effects with `effect()`

The `Fiber.effect()` method (lines 75-119) is the public API for registering disposable operations. Before accepting an effect, the Fiber calls `assertActive()` to verify the current state is appropriate for new operations.

Effects can be synchronous functions, iterables, async iterables, or promises. The method wraps each effect in a disposal wrapper that remains callable throughout the Fiber’s lifetime. When the Fiber unloads, it iterates through all registered effects and executes their cleanup logic in reverse order.

### Automatic Cleanup and Error Handling

The `_execute()` helper (invoked by `effect()`) wraps effect execution in try-catch blocks. If an effect throws synchronously or returns a rejected promise, the Fiber catches the error and routes it through `ctx.logger.error` (lines 173-182). This prevents unhandled promise rejections from crashing the entire application while marking the Fiber as failed.

When disposal occurs, the Fiber continues executing remaining cleanup routines even if individual disposal callbacks throw, ensuring that resource leaks are minimized during error conditions.

## Controlling the Plugin Lifecycle

### Starting and Stopping Plugins

While `ctx.plugin()` initiates the lifecycle, the Fiber provides direct control through several public methods:

- **`restart()`** – Forces the epoch to `__INACTIVE__` and triggers a full reload cycle
- **`dispose()`** – Registered automatically during construction, this initiates the `_unload()` sequence
- **`await()`** – Returns a promise that resolves when any pending inertia (reload or unload operations) completes, re-throwing any stored errors (lines 62-78)

These methods allow external systems to coordinate plugin availability during deployments or dependency updates.

### Handling Configuration Updates

The `update(config, noSave?)` method (lines 78-95) enables hot configuration reloading without restarting the entire application. It performs three operations:

1. Validates the new configuration against the plugin’s `Config` schema
2. Runs the `internal/update` waterfall hook to notify other services
3. Calls `restart()` to reload the plugin with the new parameters

This workflow ensures type safety and gives dependent plugins an opportunity to react to configuration changes before the target plugin restarts.

### Error Recovery and the `await()` Method

When errors occur during `_reload()` or `_unload()`, the Fiber stores the error in `_error` and transitions to the FAILED state. The `await()` method provides a safe way to interact with a potentially failed Fiber—it resolves any pending operations and re-throws the stored error if one exists. This pattern allows manager code to decide whether to retry, log, or escalate the failure.

## Practical Examples

### Creating a Plugin and Accessing Its Fiber

```typescript
import { Context } from 'cordis'

export function MyPlugin(ctx: Context) {
  // Access the Fiber managing this plugin instance
  const fiber = ctx.fiber
  
  // Register a disposable interval timer
  fiber.effect(() => {
    const timer = setInterval(() => console.log('tick'), 1000)
    return () => clearInterval(timer)
  }, 'my-plugin:timer')
}

```

The `ctx.fiber` property provides direct access to the managing Fiber instance. The `fiber.effect()` call registers a cleanup function that Cordis automatically invokes when the plugin unloads or reloads.

### Manually Restarting a Plugin

```typescript
async function restartPlugin(ctx: Context) {
  const fiber = await ctx.plugin(MyPlugin)
  await fiber.restart()
}

```

`ctx.plugin()` resolves to the Fiber instance. Calling `fiber.restart()` forces the epoch to `__INACTIVE__`, triggering `_unload()` followed by `_reload()` to refresh the plugin state.

### Updating Plugin Configuration

```typescript
// Initial load with 2000ms interval
await ctx.plugin(MyPlugin, { interval: 2000 })

// Later: update to 5000ms without full restart
const fiber = ctx.fiber
await fiber.update({ interval: 5000 })

```

The `update()` method validates the new configuration, runs update hooks, and restarts the Fiber. All effects registered previously are disposed and recreated with the new configuration context.

### Handling Errors in Effects

```typescript
fiber.effect(() => {
  // Synchronous errors are caught and logged
  throw new Error('initialization failed')
})

fiber.effect(async () => {
  // Asynchronous rejections are also handled
  await Promise.reject('async failure')
})

```

Both synchronous and asynchronous errors within effects are caught by the Fiber’s execution wrapper, logged via `ctx.logger.error`, and stored in the Fiber’s error state for inspection via `await()`.

## Summary

The Cordis Fiber class serves as the central orchestrator for plugin execution in the cordiverse/cordis framework:

- **State Machine** – Tracks plugin lifecycle through `FiberState` (PENDING, LOADING, ACTIVE, UNLOADING, DISPOSED)
- **Effect Management** – Provides `effect()` API for registering disposables that auto-cleanup on unload
- **Hot Reloading** – Uses epoch tracking (`_setEpoch()`, `_reload()`) to restart plugins when dependencies change without losing context
- **Error Boundaries** – Catches and logs errors during initialization and disposal, exposing them through `await()`
- **Configuration API** – Enables runtime updates via `update()` with schema validation and hook notification

## Frequently Asked Questions

### What is the Cordis Fiber class?

The Cordis Fiber class is the core runtime object defined in [`packages/core/src/fiber.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/fiber.ts) that manages a single plugin instance’s execution. It encapsulates the plugin’s state, configuration, disposable effects, and lifecycle transitions, acting as the intermediary between the Cordis context system and the plugin’s actual code.

### How does Cordis handle plugin reloading?

Cordis implements hot reloading through an **epoch** tracking mechanism. When injected services change or `fiber.update()` is called, the Fiber executes `_setEpoch()` to compare the new service environment against the current one. If changes are detected, `_unload()` disposes existing effects and `_reload()` re-executes the plugin callback while preserving the implementation store, allowing the plugin to restart with fresh dependencies.

### What happens when a Fiber encounters an error?

When an error occurs during effect execution, disposal, or initialization, the Fiber catches it via try-catch blocks in `_execute()` and stores it in the `_error` property. The Fiber transitions to a FAILED state, preventing further state changes until `update()` or `restart()` clears the error. The `await()` method can be used to retrieve and re-throw these errors for handling by parent contexts.

### How do I access the Fiber instance from within a plugin?

Cordis extends the `Context` interface to include a `fiber` property (declared in [`packages/core/src/fiber.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/fiber.ts), lines 8-11). Inside any plugin function, you can access `ctx.fiber` to get the current Fiber instance. This allows direct registration of effects, manual lifecycle control via `restart()`, or configuration updates through `update()`.